critsect-generic.cpp revision 3857503560316b1952243b559dec05f87c561404
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering/* $Id$ */
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering/** @file
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * IPRT - Critical Section, Generic.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering */
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering/*
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * Copyright (C) 2006-2007 Sun Microsystems, Inc.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering *
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 *
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.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering *
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 *
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
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering/*******************************************************************************
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering* Header Files *
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering*******************************************************************************/
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#include <iprt/critsect.h>
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#include <iprt/semaphore.h>
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#include <iprt/thread.h>
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#include <iprt/assert.h>
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#include <iprt/asm.h>
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#include <iprt/err.h>
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#include "internal/thread.h"
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#include "internal/strict.h"
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering/* in strict mode we're redefining this, so undefine it now for the implementation. */
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#undef RTCritSectEnter
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#undef RTCritSectTryEnter
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#undef RTCritSectEnterMultiple
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering/**
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * Initialize a critical section.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering */
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart PoetteringRTDECL(int) RTCritSectInit(PRTCRITSECT pCritSect)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering{
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering return RTCritSectInitEx(pCritSect, 0);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering}
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering/**
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * Initialize a critical section.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering *
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 Poettering */
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart PoetteringRTDECL(int) RTCritSectInitEx(PRTCRITSECT pCritSect, uint32_t fFlags)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering{
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering /*
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * Initialize the structure and
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering */
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering pCritSect->u32Magic = RTCRITSECT_MAGIC;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering pCritSect->fFlags = fFlags;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering pCritSect->cNestings = 0;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering pCritSect->cLockers = -1;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering pCritSect->NativeThreadOwner = NIL_RTNATIVETHREAD;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering pCritSect->Strict.ThreadOwner = NIL_RTTHREAD;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering pCritSect->Strict.pszEnterFile = NULL;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering pCritSect->Strict.u32EnterLine = 0;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering pCritSect->Strict.uEnterId = 0;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering int rc = RTSemEventCreate(&pCritSect->EventSem);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering if (RT_SUCCESS(rc))
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering return VINF_SUCCESS;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering AssertRC(rc);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering pCritSect->EventSem = NULL;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering pCritSect->u32Magic = (uint32_t)rc;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering return rc;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering}
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering/**
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * Enter multiple critical sections.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering *
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * This function will enter ALL the specified critical sections before returning.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering *
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 *
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 Poettering */
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart PoetteringRTDECL(int) RTCritSectEnterMultiple(unsigned cCritSects, PRTCRITSECT *papCritSects)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#ifdef RTCRITSECT_STRICT
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering{
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering return RTCritSectEnterMultipleDebug(cCritSects, papCritSects, __FILE__, __LINE__, 0);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering}
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart PoetteringRTDECL(int) RTCritSectEnterMultipleDebug(unsigned cCritSects, PRTCRITSECT *papCritSects, const char *pszFile, unsigned uLine, RTUINTPTR uId)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#endif /* RTCRITSECT_STRICT */
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering{
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering Assert(cCritSects > 0);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering Assert(VALID_PTR(papCritSects));
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering /*
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * Try get them all.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering */
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering int rc = VERR_INVALID_PARAMETER;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering unsigned i;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering for (i = 0; i < cCritSects; i++)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering {
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#ifdef RTCRITSECT_STRICT
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering rc = RTCritSectTryEnterDebug(papCritSects[i], pszFile, uLine, uId);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#else
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering rc = RTCritSectTryEnter(papCritSects[i]);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#endif
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering if (RT_FAILURE(rc))
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering break;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering }
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering if (RT_SUCCESS(rc))
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering return rc;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering /*
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * The retry loop.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering */
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering for (unsigned cTries = 0; ; cTries++)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering {
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering /*
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * We've failed, release any locks we might have gotten. ('i' is the lock that failed btw.)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering */
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering unsigned j = i;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering while (j-- > 0)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering {
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering int rc2 = RTCritSectLeave(papCritSects[j]);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering AssertRC(rc2);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering }
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering if (rc != VERR_SEM_BUSY)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering return rc;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering /*
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * Try prevent any theoretical synchronous races with other threads.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering */
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering Assert(cTries < 1000000);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering if (cTries > 10000)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering RTThreadSleep(cTries % 3);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering /*
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * Wait on the one we failed to get.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering */
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#ifdef RTCRITSECT_STRICT
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering rc = RTCritSectEnterDebug(papCritSects[i], pszFile, uLine, uId);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#else
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering rc = RTCritSectEnter(papCritSects[i]);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#endif
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering if (RT_FAILURE(rc))
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering return rc;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering /*
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * Try take the others.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering */
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering for (j = 0; j < cCritSects; j++)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering {
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering if (j != i)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering {
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#ifdef RTCRITSECT_STRICT
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering rc = RTCritSectTryEnterDebug(papCritSects[j], pszFile, uLine, uId);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#else
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering rc = RTCritSectTryEnter(papCritSects[j]);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#endif
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering if (RT_FAILURE(rc))
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering break;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering }
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering }
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering if (RT_SUCCESS(rc))
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering return rc;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering /*
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * We failed.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering */
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering if (i > j)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering {
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering int rc2 = RTCritSectLeave(papCritSects[i]);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering AssertRC(rc2);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering }
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering i = j;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering }
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering}
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering/**
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * Try enter a critical section.
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering *
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 Poettering */
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart PoetteringRTDECL(int) RTCritSectTryEnter(PRTCRITSECT pCritSect)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#ifdef RTCRITSECT_STRICT
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering{
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering return RTCritSectTryEnterDebug(pCritSect, __FILE__, __LINE__, 0);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering}
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart PoetteringRTDECL(int) RTCritSectTryEnterDebug(PRTCRITSECT pCritSect, const char *pszFile, unsigned uLine, RTUINTPTR uId)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#endif /* RTCRITSECT_STRICT */
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering{
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering Assert(pCritSect);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering Assert(pCritSect->u32Magic == RTCRITSECT_MAGIC);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering RTNATIVETHREAD NativeThreadSelf = RTThreadNativeSelf();
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#ifdef RTCRITSECT_STRICT
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering RTTHREAD ThreadSelf = RTThreadSelf();
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering if (ThreadSelf == NIL_RTTHREAD)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering RTThreadAdopt(RTTHREADTYPE_DEFAULT, 0, NULL, &ThreadSelf);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#endif
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering /*
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * Try take the lock. (cLockers is -1 if it's free)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering */
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering if (!ASMAtomicCmpXchgS32(&pCritSect->cLockers, 0, -1))
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering {
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering /*
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * Somebody is owning it (or will be soon). Perhaps it's us?
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering */
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering if (pCritSect->NativeThreadOwner == NativeThreadSelf)
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering {
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering if (!(pCritSect->fFlags & RTCRITSECT_FLAGS_NO_NESTING))
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering {
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering ASMAtomicIncS32(&pCritSect->cLockers);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering pCritSect->cNestings++;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering return VINF_SUCCESS;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering }
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering AssertMsgFailed(("Nested entry of critsect %p\n", pCritSect));
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering return VERR_SEM_NESTED;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering }
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering return VERR_SEM_BUSY;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering }
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering /*
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering * First time
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering */
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering pCritSect->cNestings = 1;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering ASMAtomicWriteHandle(&pCritSect->NativeThreadOwner, NativeThreadSelf);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#ifdef RTCRITSECT_STRICT
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering pCritSect->Strict.pszEnterFile = pszFile;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering pCritSect->Strict.u32EnterLine = uLine;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering pCritSect->Strict.uEnterId = uId;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering ASMAtomicWriteHandle(&pCritSect->Strict.ThreadOwner, ThreadSelf);
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering#endif
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering return VINF_SUCCESS;
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering}
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering
c004493cdefc1f43a3956ca529e8070f8d70be56Lennart Poettering
/**
* Enter a critical section.
*
* @returns VINF_SUCCESS on success.
* @returns VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.)
* @returns VERR_SEM_DESTROYED if RTCritSectDelete was called while waiting.
* @param pCritSect The critical section.
*/
RTDECL(int) RTCritSectEnter(PRTCRITSECT pCritSect)
#ifdef RTCRITSECT_STRICT
{
return RTCritSectEnterDebug(pCritSect, __FILE__, __LINE__, 0);
}
RTDECL(int) RTCritSectEnterDebug(PRTCRITSECT pCritSect, const char *pszFile, unsigned uLine, RTUINTPTR uId)
#endif /* RTCRITSECT_STRICT */
{
Assert(pCritSect);
Assert(pCritSect->u32Magic == RTCRITSECT_MAGIC);
RTNATIVETHREAD NativeThreadSelf = RTThreadNativeSelf();
#ifdef RTCRITSECT_STRICT
RTTHREAD ThreadSelf = RTThreadSelf();
if (ThreadSelf == NIL_RTTHREAD)
RTThreadAdopt(RTTHREADTYPE_DEFAULT, 0, NULL, &ThreadSelf);
#endif
/** If the critical section has already been destroyed, then inform the caller. */
if (pCritSect->u32Magic != RTCRITSECT_MAGIC)
return VERR_SEM_DESTROYED;
/*
* Increment the waiter counter.
* This becomes 0 when the section is free.
*/
if (ASMAtomicIncS32(&pCritSect->cLockers) > 0)
{
/*
* Nested?
*/
if (pCritSect->NativeThreadOwner == NativeThreadSelf)
{
if (!(pCritSect->fFlags & RTCRITSECT_FLAGS_NO_NESTING))
{
pCritSect->cNestings++;
return VINF_SUCCESS;
}
else
{
AssertMsgFailed(("Nested entry of critsect %p\n", pCritSect));
ASMAtomicDecS32(&pCritSect->cLockers);
return VERR_SEM_NESTED;
}
}
for (;;)
{
#ifdef RTCRITSECT_STRICT
RTThreadBlocking(ThreadSelf, RTTHREADSTATE_CRITSECT, (uintptr_t)pCritSect, pszFile, uLine, uId);
#endif
int rc = RTSemEventWait(pCritSect->EventSem, RT_INDEFINITE_WAIT);
#ifdef RTCRITSECT_STRICT
RTThreadUnblocked(ThreadSelf, RTTHREADSTATE_CRITSECT);
#endif
if (pCritSect->u32Magic != RTCRITSECT_MAGIC)
return VERR_SEM_DESTROYED;
if (rc == VINF_SUCCESS)
break;
AssertMsg(rc == VERR_TIMEOUT || rc == VERR_INTERRUPTED, ("rc=%Rrc\n", rc));
}
AssertMsg(pCritSect->NativeThreadOwner == NIL_RTNATIVETHREAD, ("pCritSect->NativeThreadOwner=%p\n", pCritSect->NativeThreadOwner));
}
/*
* First time
*/
pCritSect->cNestings = 1;
ASMAtomicWriteHandle(&pCritSect->NativeThreadOwner, NativeThreadSelf);
#ifdef RTCRITSECT_STRICT
pCritSect->Strict.pszEnterFile = pszFile;
pCritSect->Strict.u32EnterLine = uLine;
pCritSect->Strict.uEnterId = uId;
ASMAtomicWriteHandle(&pCritSect->Strict.ThreadOwner, ThreadSelf);
RTThreadWriteLockInc(ThreadSelf);
#endif
return VINF_SUCCESS;
}
/**
* Leave a critical section.
*
* @returns VINF_SUCCESS.
* @param pCritSect The critical section.
*/
RTDECL(int) RTCritSectLeave(PRTCRITSECT pCritSect)
{
/*
* Assert ownership and so on.
*/
Assert(pCritSect);
Assert(pCritSect->u32Magic == RTCRITSECT_MAGIC);
Assert(pCritSect->cNestings > 0);
Assert(pCritSect->cLockers >= 0);
Assert(pCritSect->NativeThreadOwner == RTThreadNativeSelf());
/*
* Decrement nestings, if <= 0 when we'll release the critsec.
*/
pCritSect->cNestings--;
if (pCritSect->cNestings > 0)
ASMAtomicDecS32(&pCritSect->cLockers);
else
{
/*
* Set owner to zero.
* Decrement waiters, if >= 0 then we have to wake one of them up.
*/
#ifdef RTCRITSECT_STRICT
if (pCritSect->Strict.ThreadOwner != NIL_RTTHREAD) /* May happen for PDMCritSects when entering GC/R0. */
RTThreadWriteLockDec(pCritSect->Strict.ThreadOwner);
ASMAtomicWriteHandle(&pCritSect->Strict.ThreadOwner, NIL_RTTHREAD);
#endif
ASMAtomicWriteHandle(&pCritSect->NativeThreadOwner, NIL_RTNATIVETHREAD);
if (ASMAtomicDecS32(&pCritSect->cLockers) >= 0)
{
int rc = RTSemEventSignal(pCritSect->EventSem);
AssertReleaseMsg(RT_SUCCESS(rc), ("RTSemEventSignal -> %Rrc\n", rc));
}
}
return VINF_SUCCESS;
}
/**
* Leave multiple critical sections.
*
* @returns VINF_SUCCESS.
* @param cCritSects Number of critical sections in the array.
* @param papCritSects Array of critical section pointers.
*/
RTDECL(int) RTCritSectLeaveMultiple(unsigned cCritSects, PRTCRITSECT *papCritSects)
{
int rc = VINF_SUCCESS;
for (unsigned i = 0; i < cCritSects; i++)
{
int rc2 = RTCritSectLeave(papCritSects[i]);
if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
rc = rc2;
}
return rc;
}
#ifndef RTCRITSECT_STRICT
RTDECL(int) RTCritSectEnterDebug(PRTCRITSECT pCritSect, const char *pszFile, unsigned uLine, RTUINTPTR uId)
{
return RTCritSectEnter(pCritSect);
}
RTDECL(int) RTCritSectTryEnterDebug(PRTCRITSECT pCritSect, const char *pszFile, unsigned uLine, RTUINTPTR uId)
{
return RTCritSectTryEnter(pCritSect);
}
RTDECL(int) RTCritSectEnterMultipleDebug(unsigned cCritSects, PRTCRITSECT *papCritSects, const char *pszFile, unsigned uLine, RTUINTPTR uId)
{
return RTCritSectEnterMultiple(cCritSects, papCritSects);
}
#endif /* RT_STRICT */
/**
* Deletes a critical section.
*
* @returns VINF_SUCCESS.
* @param pCritSect The critical section.
*/
RTDECL(int) RTCritSectDelete(PRTCRITSECT pCritSect)
{
/*
* Assert free waiters and so on.
*/
Assert(pCritSect);
Assert(pCritSect->u32Magic == RTCRITSECT_MAGIC);
Assert(pCritSect->cNestings == 0);
Assert(pCritSect->cLockers == -1);
Assert(pCritSect->NativeThreadOwner == NIL_RTNATIVETHREAD);
/*
* Invalidate the structure and free the mutex.
* In case someone is waiting we'll signal the semaphore cLockers + 1 times.
*/
ASMAtomicWriteU32(&pCritSect->u32Magic, ~RTCRITSECT_MAGIC);
pCritSect->fFlags = 0;
pCritSect->cNestings = 0;
pCritSect->NativeThreadOwner= NIL_RTNATIVETHREAD;
RTSEMEVENT EventSem = pCritSect->EventSem;
pCritSect->EventSem = NULL;
while (pCritSect->cLockers-- >= 0)
RTSemEventSignal(EventSem);
ASMAtomicWriteS32(&pCritSect->cLockers, -1);
int rc = RTSemEventDestroy(EventSem);
AssertRC(rc);
return rc;
}