critsect-generic.cpp revision 4b0369e0c9bcae37f2801e0f7b92509bbbaf4bec
fa9e4066f08beec538e775443c5be79dd423fcabahrens * IPRT - Critical Section, Generic.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Copyright (C) 2006-2009 Sun Microsystems, Inc.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * This file is part of VirtualBox Open Source Edition (OSE), as
fa9e4066f08beec538e775443c5be79dd423fcabahrens * available from http://www.virtualbox.org. This file is free software;
fa9e4066f08beec538e775443c5be79dd423fcabahrens * you can redistribute it and/or modify it under the terms of the GNU
fa9e4066f08beec538e775443c5be79dd423fcabahrens * General Public License (GPL) as published by the Free Software
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Foundation, in version 2 as it comes in the "COPYING" file of the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The contents of this file may alternatively be used under the terms
fa9e4066f08beec538e775443c5be79dd423fcabahrens * of the Common Development and Distribution License Version 1.0
fa9e4066f08beec538e775443c5be79dd423fcabahrens * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * VirtualBox OSE distribution, in which case the provisions of the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * CDDL are applicable instead of those of the GPL.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * You may elect to license modified versions of this file under the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * terms and conditions of either the GPL or the CDDL or both.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Clara, CA 95054 USA or visit http://www.sun.com if you need
fa9e4066f08beec538e775443c5be79dd423fcabahrens * additional information or have any questions.
fa9e4066f08beec538e775443c5be79dd423fcabahrens/*******************************************************************************
fa9e4066f08beec538e775443c5be79dd423fcabahrens* Header Files *
fa9e4066f08beec538e775443c5be79dd423fcabahrens*******************************************************************************/
fa9e4066f08beec538e775443c5be79dd423fcabahrens/* In strict mode we're redefining these, so undefine them now for the implementation. */
44cd46cadd9aab751dae6a4023c1cb5bf316d274billmRTDECL(int) RTCritSectInitEx(PRTCRITSECT pCritSect, uint32_t fFlags)
2fdbea25c2ba89186b8a6b7c6840ebc9f4dff245Aleksandr Guzovskiy * Initialize the structure and
fa9e4066f08beec538e775443c5be79dd423fcabahrens int rc = RTLockValidatorCreate(&pCritSect->pValidatorRec, NIL_RTLOCKVALIDATORCLASS, 0, NULL, pCritSect);
87e5029a3226958edab1512d6182bc74d8d80c9aahrensRTDECL(int) RTCritSectEnterMultipleDebug(size_t cCritSects, PRTCRITSECT *papCritSects, RTUINTPTR uId, RT_SRC_POS_DECL)
fa9e4066f08beec538e775443c5be79dd423fcabahrensRTDECL(int) RTCritSectEnterMultiple(size_t cCritSects, PRTCRITSECT *papCritSects)
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Try get them all.
fa9e4066f08beec538e775443c5be79dd423fcabahrens for (i = 0; i < cCritSects; i++)
fa9e4066f08beec538e775443c5be79dd423fcabahrens rc = RTCritSectTryEnterDebug(papCritSects[i], uId, RT_SRC_POS_ARGS);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * The retry loop.
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby * We've failed, release any locks we might have gotten. ('i' is the lock that failed btw.)
fa9e4066f08beec538e775443c5be79dd423fcabahrens while (j-- > 0)
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Try prevent any theoretical synchronous races with other threads.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Wait on the one we failed to get.
fa9e4066f08beec538e775443c5be79dd423fcabahrens rc = RTCritSectEnterDebug(papCritSects[i], uId, RT_SRC_POS_ARGS);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Try take the others.
fa9e4066f08beec538e775443c5be79dd423fcabahrens for (j = 0; j < cCritSects; j++)
fa9e4066f08beec538e775443c5be79dd423fcabahrens rc = RTCritSectTryEnterDebug(papCritSects[j], uId, RT_SRC_POS_ARGS);
fa9e4066f08beec538e775443c5be79dd423fcabahrensRTDECL(int) RTCritSectEnterMultiple(size_t cCritSects, PRTCRITSECT *papCritSects)
fa9e4066f08beec538e775443c5be79dd423fcabahrens return RTCritSectEnterMultipleDebug(cCritSects, papCritSects, 0, RT_SRC_POS);
fa9e4066f08beec538e775443c5be79dd423fcabahrens#else /* !RTCRITSECT_STRICT */
fa9e4066f08beec538e775443c5be79dd423fcabahrensRTDECL(int) RTCritSectEnterMultipleDebug(size_t cCritSects, PRTCRITSECT *papCritSects, RTUINTPTR uId, RT_SRC_POS_DECL)
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock return RTCritSectEnterMultiple(cCritSects, papCritSects);
99653d4ee642c6528e88224f12409a5f23060994eschrock#endif /* !RTCRITSECT_STRICT */
ca45db4129beff691dc46576c328149443788af2Chris KirbyRTDECL(int) RTCritSectTryEnterDebug(PRTCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)
088f389458728c464569a5506b58070254fa4f7dahrens RTNATIVETHREAD NativeThreadSelf = RTThreadNativeSelf();
088f389458728c464569a5506b58070254fa4f7dahrens RTThreadAdopt(RTTHREADTYPE_DEFAULT, 0, NULL, &ThreadSelf);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Try take the lock. (cLockers is -1 if it's free)
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (!ASMAtomicCmpXchgS32(&pCritSect->cLockers, 0, -1))
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Somebody is owning it (or will be soon). Perhaps it's us?
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (pCritSect->NativeThreadOwner == NativeThreadSelf)
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (!(pCritSect->fFlags & RTCRITSECT_FLAGS_NO_NESTING))
fa9e4066f08beec538e775443c5be79dd423fcabahrens AssertMsgFailed(("Nested entry of critsect %p\n", pCritSect));
fa9e4066f08beec538e775443c5be79dd423fcabahrens * First time
fa9e4066f08beec538e775443c5be79dd423fcabahrens ASMAtomicWriteHandle(&pCritSect->NativeThreadOwner, NativeThreadSelf);
fa9e4066f08beec538e775443c5be79dd423fcabahrens RTLOCKVALIDATORSRCPOS SrcPos = RTLOCKVALIDATORSRCPOS_INIT_DEBUG_API();
fa9e4066f08beec538e775443c5be79dd423fcabahrens RTLockValidatorSetOwner(pCritSect->pValidatorRec, ThreadSelf, &SrcPos);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return RTCritSectTryEnterDebug(pCritSect, 0, RT_SRC_POS);
fa9e4066f08beec538e775443c5be79dd423fcabahrens#else /* !RTCRITSECT_STRICT */
fa9e4066f08beec538e775443c5be79dd423fcabahrensRTDECL(int) RTCritSectTryEnterDebug(PRTCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)
fa9e4066f08beec538e775443c5be79dd423fcabahrens#endif /* !RTCRITSECT_STRICT */
fa9e4066f08beec538e775443c5be79dd423fcabahrensRTDECL(int) RTCritSectEnterDebug(PRTCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)
fa9e4066f08beec538e775443c5be79dd423fcabahrens RTNATIVETHREAD NativeThreadSelf = RTThreadNativeSelf();
fa9e4066f08beec538e775443c5be79dd423fcabahrens RTLOCKVALIDATORSRCPOS SrcPos = RTLOCKVALIDATORSRCPOS_INIT_DEBUG_API();
fa9e4066f08beec538e775443c5be79dd423fcabahrens RTLockValidatorCheckOrder(pCritSect->pValidatorRec, hThreadSelf, &SrcPos);
fa9e4066f08beec538e775443c5be79dd423fcabahrens /** If the critical section has already been destroyed, then inform the caller. */
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Increment the waiter counter.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * This becomes 0 when the section is free.
44cd46cadd9aab751dae6a4023c1cb5bf316d274billm if (!(pCritSect->fFlags & RTCRITSECT_FLAGS_NO_NESTING))
fa9e4066f08beec538e775443c5be79dd423fcabahrens AssertBreakpoint(); /* don't do normal assertion here, the logger uses this code too. */
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Wait for the current owner to release it.
fa9e4066f08beec538e775443c5be79dd423fcabahrens int rc9 = RTLockValidatorCheckBlocking(pCritSect->pValidatorRec, hThreadSelf, RTTHREADSTATE_CRITSECT,
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock RTThreadBlocking(hThreadSelf, RTTHREADSTATE_CRITSECT);
fa9e4066f08beec538e775443c5be79dd423fcabahrens int rc = RTSemEventWait(pCritSect->EventSem, RT_INDEFINITE_WAIT);
fa9e4066f08beec538e775443c5be79dd423fcabahrens RTThreadUnblocked(hThreadSelf, RTTHREADSTATE_CRITSECT);
fa9e4066f08beec538e775443c5be79dd423fcabahrens AssertMsg(rc == VERR_TIMEOUT || rc == VERR_INTERRUPTED, ("rc=%Rrc\n", rc));
fa9e4066f08beec538e775443c5be79dd423fcabahrens AssertMsg(pCritSect->NativeThreadOwner == NIL_RTNATIVETHREAD, ("pCritSect->NativeThreadOwner=%p\n", pCritSect->NativeThreadOwner));
fa9e4066f08beec538e775443c5be79dd423fcabahrens * First time
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock ASMAtomicWriteHandle(&pCritSect->NativeThreadOwner, NativeThreadSelf);
fa9e4066f08beec538e775443c5be79dd423fcabahrens RTLockValidatorSetOwner(pCritSect->pValidatorRec, hThreadSelf, &SrcPos);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return RTCritSectEnterDebug(pCritSect, 0, RT_SRC_POS);
fa9e4066f08beec538e775443c5be79dd423fcabahrens#else /* !RTCRITSECT_STRICT */
fa9e4066f08beec538e775443c5be79dd423fcabahrensRTDECL(int) RTCritSectEnterDebug(PRTCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)
fa9e4066f08beec538e775443c5be79dd423fcabahrens#endif /* !RTCRITSECT_STRICT */
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Assert ownership and so on.
fa9e4066f08beec538e775443c5be79dd423fcabahrens Assert(pCritSect->NativeThreadOwner == RTThreadNativeSelf());
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Decrement nestings, if <= 0 when we'll release the critsec.
3d6926289465757c3da780cea696825b0d730283Sanjeev Bagewadi * Set owner to zero.
3d6926289465757c3da780cea696825b0d730283Sanjeev Bagewadi * Decrement waiters, if >= 0 then we have to wake one of them up.
fa9e4066f08beec538e775443c5be79dd423fcabahrens ASMAtomicWriteHandle(&pCritSect->NativeThreadOwner, NIL_RTNATIVETHREAD);
fa9e4066f08beec538e775443c5be79dd423fcabahrens AssertReleaseMsg(RT_SUCCESS(rc), ("RTSemEventSignal -> %Rrc\n", rc));
fa9e4066f08beec538e775443c5be79dd423fcabahrensRTDECL(int) RTCritSectLeaveMultiple(size_t cCritSects, PRTCRITSECT *papCritSects)
d20e665c84abf083a9e8b62cca93383ecb55afdfRicardo M. Correia * Assert free waiters and so on.
d20e665c84abf083a9e8b62cca93383ecb55afdfRicardo M. Correia Assert(pCritSect->u32Magic == RTCRITSECT_MAGIC);
d20e665c84abf083a9e8b62cca93383ecb55afdfRicardo M. Correia Assert(pCritSect->NativeThreadOwner == NIL_RTNATIVETHREAD);
d20e665c84abf083a9e8b62cca93383ecb55afdfRicardo M. Correia * Invalidate the structure and free the mutex.
d20e665c84abf083a9e8b62cca93383ecb55afdfRicardo M. Correia * In case someone is waiting we'll signal the semaphore cLockers + 1 times.
d20e665c84abf083a9e8b62cca93383ecb55afdfRicardo M. Correia ASMAtomicWriteU32(&pCritSect->u32Magic, ~RTCRITSECT_MAGIC);
d20e665c84abf083a9e8b62cca93383ecb55afdfRicardo M. Correia pCritSect->NativeThreadOwner= NIL_RTNATIVETHREAD;