critsect-generic.cpp revision 3857503560316b1952243b559dec05f87c561404
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * IPRT - Critical Section, Generic.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * Copyright (C) 2006-2007 Sun Microsystems, Inc.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * This file is part of VirtualBox Open Source Edition (OSE), as
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * available from http://www.virtualbox.org. This file is free software;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * you can redistribute it and/or modify it under the terms of the GNU
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * General Public License (GPL) as published by the Free Software
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * Foundation, in version 2 as it comes in the "COPYING" file of the
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * The contents of this file may alternatively be used under the terms
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * of the Common Development and Distribution License Version 1.0
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
11c3a36649e5e5e77db499c92f3cdcbd619efd3aThomas Hindoe Paaboel Andersen * VirtualBox OSE distribution, in which case the provisions of the
11c3a36649e5e5e77db499c92f3cdcbd619efd3aThomas Hindoe Paaboel Andersen * CDDL are applicable instead of those of the GPL.
11c3a36649e5e5e77db499c92f3cdcbd619efd3aThomas Hindoe Paaboel Andersen * You may elect to license modified versions of this file under the
11c3a36649e5e5e77db499c92f3cdcbd619efd3aThomas Hindoe Paaboel Andersen * terms and conditions of either the GPL or the CDDL or both.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * Clara, CA 95054 USA or visit http://www.sun.com if you need
11c3a36649e5e5e77db499c92f3cdcbd619efd3aThomas Hindoe Paaboel Andersen * additional information or have any questions.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering/*******************************************************************************
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering* Header Files *
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering*******************************************************************************/
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering/* in strict mode we're redefining this, so undefine it now for the implementation. */
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * Initialize a critical section.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart PoetteringRTDECL(int) RTCritSectInit(PRTCRITSECT pCritSect)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * Initialize a critical section.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * @returns iprt status code.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * @param pCritSect Pointer to the critical section structure.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * @param fFlags Flags, any combination of the RTCRITSECT_FLAGS \#defines.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart PoetteringRTDECL(int) RTCritSectInitEx(PRTCRITSECT pCritSect, uint32_t fFlags)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * Initialize the structure and
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering pCritSect->NativeThreadOwner = NIL_RTNATIVETHREAD;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering pCritSect->Strict.ThreadOwner = NIL_RTTHREAD;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering int rc = RTSemEventCreate(&pCritSect->EventSem);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * Enter multiple critical sections.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * This function will enter ALL the specified critical sections before returning.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * @returns VINF_SUCCESS on success.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * @returns VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * @returns VERR_SEM_DESTROYED if RTCritSectDelete was called while waiting.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * @param cCritSects Number of critical sections in the array.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * @param papCritSects Array of critical section pointers.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * @remark Please note that this function will not necessarily come out favourable in a
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * fight with other threads which are using the normal RTCritSectEnter() function.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * Therefore, avoid having to enter multiple critical sections!
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart PoetteringRTDECL(int) RTCritSectEnterMultiple(unsigned cCritSects, PRTCRITSECT *papCritSects)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering return RTCritSectEnterMultipleDebug(cCritSects, papCritSects, __FILE__, __LINE__, 0);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart PoetteringRTDECL(int) RTCritSectEnterMultipleDebug(unsigned cCritSects, PRTCRITSECT *papCritSects, const char *pszFile, unsigned uLine, RTUINTPTR uId)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#endif /* RTCRITSECT_STRICT */
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * Try get them all.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering for (i = 0; i < cCritSects; i++)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering rc = RTCritSectTryEnterDebug(papCritSects[i], pszFile, uLine, uId);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering rc = RTCritSectTryEnter(papCritSects[i]);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * The retry loop.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * We've failed, release any locks we might have gotten. ('i' is the lock that failed btw.)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering unsigned j = i;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering while (j-- > 0)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering int rc2 = RTCritSectLeave(papCritSects[j]);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * Try prevent any theoretical synchronous races with other threads.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * Wait on the one we failed to get.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering rc = RTCritSectEnterDebug(papCritSects[i], pszFile, uLine, uId);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * Try take the others.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering for (j = 0; j < cCritSects; j++)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering rc = RTCritSectTryEnterDebug(papCritSects[j], pszFile, uLine, uId);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering rc = RTCritSectTryEnter(papCritSects[j]);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering int rc2 = RTCritSectLeave(papCritSects[i]);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * Try enter a critical section.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * @returns VINF_SUCCESS on success.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * @returns VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * @returns VERR_SEM_DESTROYED if RTCritSectDelete was called while waiting.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * @param pCritSect The critical section.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart PoetteringRTDECL(int) RTCritSectTryEnter(PRTCRITSECT pCritSect)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering return RTCritSectTryEnterDebug(pCritSect, __FILE__, __LINE__, 0);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart PoetteringRTDECL(int) RTCritSectTryEnterDebug(PRTCRITSECT pCritSect, const char *pszFile, unsigned uLine, RTUINTPTR uId)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#endif /* RTCRITSECT_STRICT */
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering Assert(pCritSect->u32Magic == RTCRITSECT_MAGIC);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering RTNATIVETHREAD NativeThreadSelf = RTThreadNativeSelf();
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering RTThreadAdopt(RTTHREADTYPE_DEFAULT, 0, NULL, &ThreadSelf);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * Try take the lock. (cLockers is -1 if it's free)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering if (!ASMAtomicCmpXchgS32(&pCritSect->cLockers, 0, -1))
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * Somebody is owning it (or will be soon). Perhaps it's us?
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering if (pCritSect->NativeThreadOwner == NativeThreadSelf)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering if (!(pCritSect->fFlags & RTCRITSECT_FLAGS_NO_NESTING))
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering AssertMsgFailed(("Nested entry of critsect %p\n", pCritSect));
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering ASMAtomicWriteHandle(&pCritSect->NativeThreadOwner, NativeThreadSelf);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering pCritSect->Strict.pszEnterFile = pszFile;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering ASMAtomicWriteHandle(&pCritSect->Strict.ThreadOwner, ThreadSelf);
#ifdef RTCRITSECT_STRICT
RTDECL(int) RTCritSectEnterDebug(PRTCRITSECT pCritSect, const char *pszFile, unsigned uLine, RTUINTPTR uId)
#ifdef RTCRITSECT_STRICT
return VERR_SEM_DESTROYED;
return VINF_SUCCESS;
return VERR_SEM_NESTED;
#ifdef RTCRITSECT_STRICT
#ifdef RTCRITSECT_STRICT
return VERR_SEM_DESTROYED;
AssertMsg(pCritSect->NativeThreadOwner == NIL_RTNATIVETHREAD, ("pCritSect->NativeThreadOwner=%p\n", pCritSect->NativeThreadOwner));
#ifdef RTCRITSECT_STRICT
return VINF_SUCCESS;
#ifdef RTCRITSECT_STRICT
if (pCritSect->Strict.ThreadOwner != NIL_RTTHREAD) /* May happen for PDMCritSects when entering GC/R0. */
return VINF_SUCCESS;
for (unsigned i = 0; i < cCritSects; i++)
return rc;
#ifndef RTCRITSECT_STRICT
RTDECL(int) RTCritSectEnterDebug(PRTCRITSECT pCritSect, const char *pszFile, unsigned uLine, RTUINTPTR uId)
RTDECL(int) RTCritSectTryEnterDebug(PRTCRITSECT pCritSect, const char *pszFile, unsigned uLine, RTUINTPTR uId)
RTDECL(int) RTCritSectEnterMultipleDebug(unsigned cCritSects, PRTCRITSECT *papCritSects, const char *pszFile, unsigned uLine, RTUINTPTR uId)
return rc;