semrw-posix.cpp revision 2805b95732a8d26015a397626b96049a6e6573e7
35473cad6d5d5b57348c66f0cfdd7d51d6071ee7vboxsync * IPRT - Read-Write Semaphore, POSIX.
f001425d2b0a661d4cd1f7ea07b4e7454538c829vboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
fcae7923a3c756b333f1e33eba002edf4448fb54vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
fcae7923a3c756b333f1e33eba002edf4448fb54vboxsync * available from http://www.virtualbox.org. This file is free software;
fcae7923a3c756b333f1e33eba002edf4448fb54vboxsync * you can redistribute it and/or modify it under the terms of the GNU
fcae7923a3c756b333f1e33eba002edf4448fb54vboxsync * General Public License (GPL) as published by the Free Software
fcae7923a3c756b333f1e33eba002edf4448fb54vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
fcae7923a3c756b333f1e33eba002edf4448fb54vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
fcae7923a3c756b333f1e33eba002edf4448fb54vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
f001425d2b0a661d4cd1f7ea07b4e7454538c829vboxsync * The contents of this file may alternatively be used under the terms
f001425d2b0a661d4cd1f7ea07b4e7454538c829vboxsync * of the Common Development and Distribution License Version 1.0
f001425d2b0a661d4cd1f7ea07b4e7454538c829vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
f001425d2b0a661d4cd1f7ea07b4e7454538c829vboxsync * VirtualBox OSE distribution, in which case the provisions of the
f001425d2b0a661d4cd1f7ea07b4e7454538c829vboxsync * CDDL are applicable instead of those of the GPL.
f001425d2b0a661d4cd1f7ea07b4e7454538c829vboxsync * You may elect to license modified versions of this file under the
f001425d2b0a661d4cd1f7ea07b4e7454538c829vboxsync * terms and conditions of either the GPL or the CDDL or both.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * additional information or have any questions.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync/*******************************************************************************
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync* Header Files *
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync*******************************************************************************/
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync/*******************************************************************************
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync* Defined Constants And Macros *
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync*******************************************************************************/
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync/** @todo move this to r3/posix/something.h. */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync# define ATOMIC_GET_PTHREAD_T(pvVar, pThread) ASMAtomicReadSize(pvVar, pThread)
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync# define ATOMIC_SET_PTHREAD_T(pvVar, pThread) ASMAtomicWriteSize(pvVar, pThread)
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync# define ATOMIC_GET_PTHREAD_T(pvVar, pThread) do { *(pThread) = (pthread_t)ASMAtomicReadPtr((void *volatile *)pvVar); } while (0)
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync# define ATOMIC_SET_PTHREAD_T(pvVar, pThread) ASMAtomicWritePtr((void *volatile *)pvVar, (void *)pThread)
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync/*******************************************************************************
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync* Structures and Typedefs *
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync*******************************************************************************/
561b8d2b46fb10887829b7e4d7d29447817adbddvboxsync/** Posix internal representation of a read-write semaphore. */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync /** The usual magic. (RTSEMRW_MAGIC) */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync /** The number of readers.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * (For preventing screwing up the lock on linux). */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync /** Number of write recursions. */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync /** Number of read recursions by the writer. */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync /** The write owner of the lock. */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync /** pthread rwlock. */
fb4eaa62a6bbeb82a89703d833d39339783feb4avboxsync /** The validator record for the writer. */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync /** The validator record for the readers. */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync/* No debug wrapping here. */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Allocate handle.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync struct RTSEMRWINTERNAL *pThis = (struct RTSEMRWINTERNAL *)RTMemAlloc(sizeof(struct RTSEMRWINTERNAL));
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Create the rwlock.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync RTLockValidatorRecExclInit(&pThis->ValidatorWrite, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, "RTSemRW", pThis, true);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync RTLockValidatorRecSharedInit(&pThis->ValidatorRead, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, "RTSemRW", pThis, false /*fSignaller*/, true);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync RTLockValidatorRecMakeSiblings(&pThis->ValidatorWrite.Core, &pThis->ValidatorRead.Core);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Validate input, nil handle is fine.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
f48c3167a0f99da174686b66dc4e666f38ecae46vboxsync * Try destroy it.
f48c3167a0f99da174686b66dc4e666f38ecae46vboxsync AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTSEMRW_MAGIC, RTSEMRW_MAGIC), VERR_INVALID_HANDLE);
6479169ec893c18a646cec595e4e214492d180f0vboxsync RTLockValidatorRecSharedDelete(&pThis->ValidatorRead);
6479169ec893c18a646cec595e4e214492d180f0vboxsync RTLockValidatorRecExclDelete(&pThis->ValidatorWrite);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync ASMAtomicWriteU32(&pThis->u32Magic, RTSEMRW_MAGIC);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync AssertMsgFailed(("Failed to destroy read-write sem %p, rc=%d.\n", RWSem, rc));
1403063c7e0c0a072d59e323b66068b06278fb9avboxsyncDECL_FORCE_INLINE(int) rtSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies, PCRTLOCKVALSRCPOS pSrcPos)
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Validate input.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Check if it's the writer (implement write+read recursion).
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync int rc9 = RTLockValidatorRecExclRecursionMixed(&pThis->ValidatorWrite, &pThis->ValidatorRead.Core, pSrcPos);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Try lock it.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync int rc9 = RTLockValidatorRecSharedCheckOrderAndBlocking(&pThis->ValidatorRead, hThreadSelf, pSrcPos, true,
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_READ, true);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync /* take rwlock */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_READ);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync AssertMsgFailed(("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync#else /* !RT_OS_DARWIN */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Get current time and calc end of wait time.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync /* take rwlock */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync int rc = pthread_rwlock_timedrdlock(&pThis->RWLock, &ts);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_READ);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync#endif /* !RT_OS_DARWIN */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync RTLockValidatorRecSharedAddOwner(&pThis->ValidatorRead, hThreadSelf, pSrcPos);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsyncRTDECL(int) RTSemRWRequestRead(RTSEMRW RWSem, unsigned cMillies)
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync return rtSemRWRequestRead(RWSem, cMillies, &SrcPos);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsyncRTDECL(int) RTSemRWRequestReadDebug(RTSEMRW RWSem, unsigned cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync return rtSemRWRequestRead(RWSem, cMillies, &SrcPos);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsyncRTDECL(int) RTSemRWRequestReadNoResume(RTSEMRW RWSem, unsigned cMillies)
f48c3167a0f99da174686b66dc4e666f38ecae46vboxsync /* EINTR isn't returned by the wait functions we're using. */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync return rtSemRWRequestRead(RWSem, cMillies, &SrcPos);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsyncRTDECL(int) RTSemRWRequestReadNoResumeDebug(RTSEMRW RWSem, unsigned cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync return rtSemRWRequestRead(RWSem, cMillies, &SrcPos);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Validate input.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Check if it's the writer.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync AssertMsgReturn(pThis->cWriterReads > 0, ("pThis=%p\n", pThis), VERR_NOT_OWNER);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync int rc9 = RTLockValidatorRecExclUnwindMixed(&pThis->ValidatorWrite, &pThis->ValidatorRead.Core);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Try unlock it.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync int rc9 = RTLockValidatorRecSharedCheckAndRelease(&pThis->ValidatorRead, RTThreadSelf());
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync#ifdef RT_OS_LINUX /* glibc (at least 2.8) may screw up when unlocking a lock we don't own. */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync AssertMsgFailed(("Failed read unlock read-write sem %p, rc=%d.\n", RWSem, rc));
1403063c7e0c0a072d59e323b66068b06278fb9avboxsyncDECL_FORCE_INLINE(int) rtSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies, PCRTLOCKVALSRCPOS pSrcPos)
f48c3167a0f99da174686b66dc4e666f38ecae46vboxsync * Validate input.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Recursion?
6479169ec893c18a646cec595e4e214492d180f0vboxsync int rc9 = RTLockValidatorRecExclRecursion(&pThis->ValidatorWrite, pSrcPos);
6479169ec893c18a646cec595e4e214492d180f0vboxsync * Try lock it.
6479169ec893c18a646cec595e4e214492d180f0vboxsync int rc9 = RTLockValidatorRecExclCheckOrderAndBlocking(&pThis->ValidatorWrite, hThreadSelf, pSrcPos, true,
6479169ec893c18a646cec595e4e214492d180f0vboxsync RTThreadBlocking(hThreadSelf, RTTHREADSTATE_RW_WRITE, true);
6479169ec893c18a646cec595e4e214492d180f0vboxsync /* take rwlock */
6479169ec893c18a646cec595e4e214492d180f0vboxsync RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_WRITE);
6479169ec893c18a646cec595e4e214492d180f0vboxsync AssertMsgFailed(("Failed write lock read-write sem %p, rc=%d.\n", RWSem, rc));
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync AssertMsgFailed(("Not implemented on Darwin yet because of incomplete pthreads API."));
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync#else /* !RT_OS_DARWIN */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Get current time and calc end of wait time.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync /* take rwlock */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync int rc = pthread_rwlock_timedwrlock(&pThis->RWLock, &ts);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_RW_WRITE);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync AssertMsg(rc == ETIMEDOUT, ("Failed read lock read-write sem %p, rc=%d.\n", RWSem, rc));
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync#endif /* !RT_OS_DARWIN */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync RTLockValidatorRecExclSetOwner(&pThis->ValidatorWrite, hThreadSelf, pSrcPos, true);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsyncRTDECL(int) RTSemRWRequestWrite(RTSEMRW RWSem, unsigned cMillies)
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync return rtSemRWRequestWrite(RWSem, cMillies, &SrcPos);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsyncRTDECL(int) RTSemRWRequestWriteDebug(RTSEMRW RWSem, unsigned cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync return rtSemRWRequestWrite(RWSem, cMillies, &SrcPos);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsyncRTDECL(int) RTSemRWRequestWriteNoResume(RTSEMRW RWSem, unsigned cMillies)
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync /* EINTR isn't returned by the wait functions we're using. */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync return rtSemRWRequestWrite(RWSem, cMillies, &SrcPos);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsyncRTDECL(int) RTSemRWRequestWriteNoResumeDebug(RTSEMRW RWSem, unsigned cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync /* EINTR isn't returned by the wait functions we're using. */
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync return rtSemRWRequestWrite(RWSem, cMillies, &SrcPos);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Validate input.
f48c3167a0f99da174686b66dc4e666f38ecae46vboxsync ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Verify ownership and implement recursion.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync AssertMsgReturn(Writer == Self, ("pThis=%p\n", pThis), VERR_NOT_OWNER);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync AssertReturn(pThis->cWriterReads == 0 || pThis->cWrites > 1, VERR_WRONG_ORDER);
6479169ec893c18a646cec595e4e214492d180f0vboxsync int rc9 = RTLockValidatorRecExclUnwind(&pThis->ValidatorWrite);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Try unlock it.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync int rc9 = RTLockValidatorRecExclReleaseOwner(&pThis->ValidatorWrite, true);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync ATOMIC_SET_PTHREAD_T(&pThis->Writer, (pthread_t)-1);
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync AssertMsgFailed(("Failed write unlock read-write sem %p, rc=%d.\n", RWSem, rc));
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Validate input.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Check ownership.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsyncRTDECL(uint32_t) RTSemRWGetWriteRecursion(RTSEMRW RWSem)
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Validate input.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Return the requested data.
6479169ec893c18a646cec595e4e214492d180f0vboxsyncRTDECL(uint32_t) RTSemRWGetWriterReadRecursion(RTSEMRW RWSem)
6479169ec893c18a646cec595e4e214492d180f0vboxsync * Validate input.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
1519f0483877fddc0a03ab7e3382124f889bb36avboxsync * Return the requested data.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Validate input.
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
1403063c7e0c0a072d59e323b66068b06278fb9avboxsync * Return the requested data.