semmutex-linux.cpp revision 89dfdbb56cf9dddad3c7685b41bda1e4e4c1d6f9
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/* $Id$ */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/** @file
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * innotek Portable Runtime - Mutex Semaphore, Linux (2.6.x+).
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/*
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync * Copyright (C) 2006-2007 innotek GmbH
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync *
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * available from http://www.virtualbox.org. This file is free software;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * you can redistribute it and/or modify it under the terms of the GNU
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * General Public License (GPL) as published by the Free Software
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync *
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * The contents of this file may alternatively be used under the terms
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * of the Common Development and Distribution License Version 1.0
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * VirtualBox OSE distribution, in which case the provisions of the
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * CDDL are applicable instead of those of the GPL.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync *
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * You may elect to license modified versions of this file under the
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * terms and conditions of either the GPL or the CDDL or both.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync/*******************************************************************************
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync* Header Files *
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync*******************************************************************************/
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#include <iprt/semaphore.h>
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#include <iprt/assert.h>
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync#include <iprt/alloc.h>
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#include <iprt/asm.h>
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#include <iprt/err.h>
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#include "internal/magics.h"
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#include <errno.h>
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#include <limits.h>
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#include <pthread.h>
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#include <unistd.h>
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#include <sys/time.h>
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#include <sys/syscall.h>
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#if 0 /* With 2.6.17 futex.h has become C++ unfriendly. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync# include <linux/futex.h>
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#else
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync# define FUTEX_WAIT 0
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync# define FUTEX_WAKE 1
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync#endif
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/*******************************************************************************
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync* Structures and Typedefs *
76cb9831bbeaff3bb30068363e35660a776736c4vboxsync*******************************************************************************/
d68336e34409fd767807d5ef641a305de4d9ee59vboxsync/**
d68336e34409fd767807d5ef641a305de4d9ee59vboxsync * Linux internal representation of a Mutex semaphore.
76cb9831bbeaff3bb30068363e35660a776736c4vboxsync */
76cb9831bbeaff3bb30068363e35660a776736c4vboxsyncstruct RTSEMMUTEXINTERNAL
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync{
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** The futex state variable.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * 0 means unlocked.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * 1 means locked, no waiters.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * 2 means locked, one or more waiters.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync int32_t volatile iState;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Nesting count. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync uint32_t volatile cNesting;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** The owner of the mutex. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync pthread_t volatile Owner;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Magic value. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync intptr_t volatile iMagic;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync};
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/**
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Wrapper for the futex syscall.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncstatic long sys_futex(int32_t volatile *uaddr, int op, int val, struct timespec *utime, int32_t *uaddr2, int val3)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync{
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync errno = 0;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync long rc = syscall(__NR_futex, uaddr, op, val, utime, uaddr2, val3);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (rc < 0)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync Assert(rc == -1);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync rc = -errno;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync return rc;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync}
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncRTDECL(int) RTSemMutexCreate(PRTSEMMUTEX pMutexSem)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync{
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /*
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Allocate semaphore handle.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync struct RTSEMMUTEXINTERNAL *pThis = (struct RTSEMMUTEXINTERNAL *)RTMemAlloc(sizeof(struct RTSEMMUTEXINTERNAL));
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync if (pThis)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync {
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync pThis->iMagic = RTSEMMUTEX_MAGIC;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync pThis->iState = 0;
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync pThis->Owner = (pthread_t)~0;
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync pThis->cNesting = 0;
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync *pMutexSem = pThis;
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync return VINF_SUCCESS;
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync }
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync return VERR_NO_MEMORY;
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync}
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync
619824b60d668e6e43f385ef78cf06e13d43aab6vboxsync
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsyncRTDECL(int) RTSemMutexDestroy(RTSEMMUTEX MutexSem)
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync{
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync /*
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync * Validate input.
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync */
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync if (MutexSem == NIL_RTSEMMUTEX)
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync return VERR_INVALID_HANDLE;
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync struct RTSEMMUTEXINTERNAL *pThis = MutexSem;
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync AssertMsgReturn(pThis->iMagic == RTSEMMUTEX_MAGIC,
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync ("MutexSem=%p iMagic=%#x\n", pThis, pThis->iMagic),
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync VERR_INVALID_HANDLE);
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync /*
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync * Invalidate the semaphore and wake up anyone waiting on it.
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync ASMAtomicXchgSize(&pThis->iMagic, RTSEMMUTEX_MAGIC + 1);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (ASMAtomicXchgS32(&pThis->iState, 0) > 0)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync sys_futex(&pThis->iState, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync usleep(1000);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync }
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync pThis->Owner = (pthread_t)~0;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync pThis->cNesting = 0;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /*
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Free the semaphore memory and be gone.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync RTMemFree(pThis);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync return VINF_SUCCESS;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync}
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncstatic int rtsemMutexRequest(RTSEMMUTEX MutexSem, unsigned cMillies, bool fAutoResume)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync{
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /*
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Validate input.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync struct RTSEMMUTEXINTERNAL *pThis = MutexSem;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync AssertMsgReturn(pThis->iMagic == RTSEMMUTEX_MAGIC,
b3109af8dcc2a3da7f424aa05a4e84a64bf1c43fvboxsync ("MutexSem=%p iMagic=%#x\n", pThis, pThis->iMagic),
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync VERR_INVALID_HANDLE);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /*
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Check if nested request.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync pthread_t Self = pthread_self();
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync if ( pThis->Owner == Self
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync && pThis->cNesting > 0)
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync {
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync pThis->cNesting++;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync return VINF_SUCCESS;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync }
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /*
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Convert timeout value.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync struct timespec ts;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync struct timespec *pTimeout = NULL;
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync if (cMillies != RT_INDEFINITE_WAIT)
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync ts.tv_sec = cMillies / 1000;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync ts.tv_nsec = (cMillies % 1000) * 1000000;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync pTimeout = &ts;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync }
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /*
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Lock the mutex.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync if (RT_UNLIKELY(!ASMAtomicCmpXchgS32(&pThis->iState, 1, 0)))
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync {
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync for (;;)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync {
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync int32_t iOld = ASMAtomicXchgS32(&pThis->iState, 2);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /*
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Was the lock released in the meantime? This is unlikely (but possible)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync if (RT_UNLIKELY(iOld == 0))
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync break;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /*
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Go to sleep.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync long rc = sys_futex(&pThis->iState, FUTEX_WAIT, 2, pTimeout, NULL, 0);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync if (RT_UNLIKELY(pThis->iMagic != RTSEMMUTEX_MAGIC))
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync return VERR_SEM_DESTROYED;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync /*
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * Act on the wakup code.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (rc == -ETIMEDOUT)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync Assert(pTimeout);
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync return VERR_TIMEOUT;
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync }
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync if (rc == 0)
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync /* we'll leave the loop now unless another thread is faster */;
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync else if (rc == -EWOULDBLOCK)
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync /* retry with new value. */;
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync else if (rc == -EINTR)
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync {
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync if (!fAutoResume)
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync return VERR_INTERRUPTED;
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync }
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync else
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync {
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync /* this shouldn't happen! */
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync AssertMsgFailed(("rc=%ld errno=%d\n", rc, errno));
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync return RTErrConvertFromErrno(rc);
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync }
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync }
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync /*
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync * When leaving this loop, iState is set to 2. This means that we gained the
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync * Lock and there are _possibly_ some waiters. We don't know exactly as another
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync * thread might entered this loop at nearly the same time. Therefore we will
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync * call futex_wakeup once too often (if _no_ other thread entered this loop).
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * The key problem is the simple futex_wait test for x != y (iState != 2) in
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * our case).
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync }
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /*
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync * Set the owner and nesting.
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync */
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync pThis->Owner = Self;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync ASMAtomicXchgU32(&pThis->cNesting, 1);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync return VINF_SUCCESS;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync}
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncRTDECL(int) RTSemMutexRequest(RTSEMMUTEX MutexSem, unsigned cMillies)
0780b79e94db3b60fb4a3057df7c64ba8b1cb75dvboxsync{
0780b79e94db3b60fb4a3057df7c64ba8b1cb75dvboxsync int rc = rtsemMutexRequest(MutexSem, cMillies, true);
0780b79e94db3b60fb4a3057df7c64ba8b1cb75dvboxsync Assert(rc != VERR_INTERRUPTED);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync return rc;
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync}
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsyncRTDECL(int) RTSemMutexRequestNoResume(RTSEMMUTEX MutexSem, unsigned cMillies)
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync{
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync return rtsemMutexRequest(MutexSem, cMillies, false);
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync}
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsyncRTDECL(int) RTSemMutexRelease(RTSEMMUTEX MutexSem)
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync{
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync /*
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync * Validate input.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync struct RTSEMMUTEXINTERNAL *pThis = MutexSem;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync AssertMsgReturn(pThis->iMagic == RTSEMMUTEX_MAGIC,
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync ("MutexSem=%p iMagic=%#x\n", pThis, pThis->iMagic),
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync VERR_INVALID_HANDLE);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /*
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Check if nested.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync pthread_t Self = pthread_self();
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync if (RT_UNLIKELY( pThis->Owner != Self
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync || pThis->cNesting == 0))
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync {
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync AssertMsgFailed(("Not owner of mutex %p!! Self=%08x Owner=%08x cNesting=%d\n",
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync pThis, Self, pThis->Owner, pThis->cNesting));
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync return VERR_NOT_OWNER;
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync }
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync /*
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync * If nested we'll just pop a nesting.
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync */
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync if (pThis->cNesting > 1)
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync {
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync pThis->cNesting--;
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync return VINF_SUCCESS;
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync }
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync /*
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync * Clear the state. (cNesting == 1)
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync */
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync pThis->Owner = (pthread_t)~0;
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync ASMAtomicXchgU32(&pThis->cNesting, 0);
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync /*
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync * Release the mutex.
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync */
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync int32_t iNew = ASMAtomicDecS32(&pThis->iState);
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync if (iNew != 0)
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync {
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync /* somebody is waiting, try wake up one of them. */
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync ASMAtomicXchgS32(&pThis->iState, 0);
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync (void)sys_futex(&pThis->iState, FUTEX_WAKE, 1, NULL, NULL, 0);
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync }
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync return VINF_SUCCESS;
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync}
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync