lockvalidator.cpp revision 645c172620d19e7aceca8b5ba9a904619681099d
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/* $Id$ */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** @file
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * IPRT - Lock Validator.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/*
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Copyright (C) 2009-2012 Oracle Corporation
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * available from http://www.virtualbox.org. This file is free software;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * you can redistribute it and/or modify it under the terms of the GNU
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * General Public License (GPL) as published by the Free Software
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * The contents of this file may alternatively be used under the terms
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * of the Common Development and Distribution License Version 1.0
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * VirtualBox OSE distribution, in which case the provisions of the
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * CDDL are applicable instead of those of the GPL.
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * You may elect to license modified versions of this file under the
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * terms and conditions of either the GPL or the CDDL or both.
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync */
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/*******************************************************************************
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync* Header Files *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync*******************************************************************************/
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <iprt/lockvalidator.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include "internal/iprt.h"
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <iprt/asm.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <iprt/assert.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <iprt/env.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <iprt/err.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <iprt/mem.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <iprt/once.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <iprt/semaphore.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <iprt/string.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <iprt/thread.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include "internal/lockvalidator.h"
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include "internal/magics.h"
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include "internal/strhash.h"
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include "internal/thread.h"
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/*******************************************************************************
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync* Defined Constants And Macros *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync*******************************************************************************/
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** Macro that asserts that a pointer is aligned correctly.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Only used when fighting bugs. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#if 1
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync# define RTLOCKVAL_ASSERT_PTR_ALIGN(p) \
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertMsg(!((uintptr_t)(p) & (sizeof(uintptr_t) - 1)), ("%p\n", (p)));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#else
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync# define RTLOCKVAL_ASSERT_PTR_ALIGN(p) do { } while (0)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#endif
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** Hashes the class handle (pointer) into an apPriorLocksHash index. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#define RTLOCKVALCLASS_HASH(hClass) \
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ( ((uintptr_t)(hClass) >> 6 ) \
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync % ( RT_SIZEOFMEMB(RTLOCKVALCLASSINT, apPriorLocksHash) \
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync / sizeof(PRTLOCKVALCLASSREF)) )
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync/** The max value for RTLOCKVALCLASSINT::cRefs. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#define RTLOCKVALCLASS_MAX_REFS UINT32_C(0xffff0000)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** The max value for RTLOCKVALCLASSREF::cLookups. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#define RTLOCKVALCLASSREF_MAX_LOOKUPS UINT32_C(0xfffe0000)
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync/** The absolute max value for RTLOCKVALCLASSREF::cLookups at which it will
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync * be set back to RTLOCKVALCLASSREF_MAX_LOOKUPS. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#define RTLOCKVALCLASSREF_MAX_LOOKUPS_FIX UINT32_C(0xffff0000)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync/** @def RTLOCKVAL_WITH_RECURSION_RECORDS
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Enable recursion records. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#if defined(IN_RING3) || defined(DOXYGEN_RUNNING)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync# define RTLOCKVAL_WITH_RECURSION_RECORDS 1
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#endif
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** @def RTLOCKVAL_WITH_VERBOSE_DUMPS
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Enables some extra verbosity in the lock dumping. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#if defined(DOXYGEN_RUNNING)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync# define RTLOCKVAL_WITH_VERBOSE_DUMPS
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync#endif
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync/** @def RTLOCKVAL_WITH_CLASS_HASH_STATS
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync * Enables collection prior class hash lookup statistics, dumping them when
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync * complaining about the class. */
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync#if defined(DEBUG) || defined(DOXYGEN_RUNNING)
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync# define RTLOCKVAL_WITH_CLASS_HASH_STATS
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync#endif
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync/*******************************************************************************
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync* Structures and Typedefs *
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync*******************************************************************************/
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync/**
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync * Deadlock detection stack entry.
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsynctypedef struct RTLOCKVALDDENTRY
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync{
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync /** The current record. */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync PRTLOCKVALRECUNION pRec;
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync /** The current entry number if pRec is a shared one. */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync uint32_t iEntry;
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync /** The thread state of the thread we followed to get to pFirstSibling.
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync * This is only used for validating a deadlock stack. */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync RTTHREADSTATE enmState;
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync /** The thread we followed to get to pFirstSibling.
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync * This is only used for validating a deadlock stack. */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync PRTTHREADINT pThread;
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync /** What pThread is waiting on, i.e. where we entered the circular list of
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync * siblings. This is used for validating a deadlock stack as well as
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync * terminating the sibling walk. */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync PRTLOCKVALRECUNION pFirstSibling;
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync} RTLOCKVALDDENTRY;
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync/**
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync * Deadlock detection stack.
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsynctypedef struct RTLOCKVALDDSTACK
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync{
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync /** The number stack entries. */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync uint32_t c;
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync /** The stack entries. */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync RTLOCKVALDDENTRY a[32];
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync} RTLOCKVALDDSTACK;
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync/** Pointer to a deadlock detection stack. */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsynctypedef RTLOCKVALDDSTACK *PRTLOCKVALDDSTACK;
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync/**
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync * Reference to another class.
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsynctypedef struct RTLOCKVALCLASSREF
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync{
56602ba12f2388501d594c83fbbf77b4b16f8f4fvboxsync /** The class. */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync RTLOCKVALCLASS hClass;
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync /** The number of lookups of this class. */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync uint32_t volatile cLookups;
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync /** Indicates whether the entry was added automatically during order checking
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync * (true) or manually via the API (false). */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync bool fAutodidacticism;
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync /** Reserved / explicit alignment padding. */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync bool afReserved[3];
56602ba12f2388501d594c83fbbf77b4b16f8f4fvboxsync} RTLOCKVALCLASSREF;
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync/** Pointer to a class reference. */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsynctypedef RTLOCKVALCLASSREF *PRTLOCKVALCLASSREF;
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync/** Pointer to a chunk of class references. */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsynctypedef struct RTLOCKVALCLASSREFCHUNK *PRTLOCKVALCLASSREFCHUNK;
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync/**
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync * Chunk of class references.
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync */
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsynctypedef struct RTLOCKVALCLASSREFCHUNK
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync{
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync /** Array of refs. */
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync#if 0 /** @todo for testing allocation of new chunks. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTLOCKVALCLASSREF aRefs[ARCH_BITS == 32 ? 10 : 8];
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#else
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTLOCKVALCLASSREF aRefs[2];
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync#endif
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync /** Pointer to the next chunk. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTLOCKVALCLASSREFCHUNK volatile pNext;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync} RTLOCKVALCLASSREFCHUNK;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/**
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Lock class.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsynctypedef struct RTLOCKVALCLASSINT
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** AVL node core. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AVLLU32NODECORE Core;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** Magic value (RTLOCKVALCLASS_MAGIC). */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync uint32_t volatile u32Magic;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** Reference counter. See RTLOCKVALCLASS_MAX_REFS. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync uint32_t volatile cRefs;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** Whether the class is allowed to teach it self new locking order rules. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync bool fAutodidact;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** Whether to allow recursion. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync bool fRecursionOk;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** Strict release order. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync bool fStrictReleaseOrder;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** Whether this class is in the tree. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync bool fInTree;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** Donate a reference to the next retainer. This is a hack to make
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * RTLockValidatorClassCreateUnique work. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync bool volatile fDonateRefToNextRetainer;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** Reserved future use / explicit alignment. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync bool afReserved[3];
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync /** The minimum wait interval for which we do deadlock detection
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync * (milliseconds). */
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync RTMSINTERVAL cMsMinDeadlock;
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync /** The minimum wait interval for which we do order checks (milliseconds). */
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync RTMSINTERVAL cMsMinOrder;
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync /** More padding. */
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync uint32_t au32Reserved[ARCH_BITS == 32 ? 5 : 2];
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync /** Classes that may be taken prior to this one.
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync * This is a linked list where each node contains a chunk of locks so that we
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync * reduce the number of allocations as well as localize the data. */
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync RTLOCKVALCLASSREFCHUNK PriorLocks;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** Hash table containing frequently encountered prior locks. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTLOCKVALCLASSREF apPriorLocksHash[17];
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** Class name. (Allocated after the end of the block as usual.) */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync char const *pszName;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** Where this class was created.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * This is mainly used for finding automatically created lock classes.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @remarks The strings are stored after this structure so we won't crash
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * if the class lives longer than the module (dll/so/dylib) that
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * spawned it. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTLOCKVALSRCPOS CreatePos;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#ifdef RTLOCKVAL_WITH_CLASS_HASH_STATS
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** Hash hits. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync uint32_t volatile cHashHits;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** Hash misses. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync uint32_t volatile cHashMisses;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#endif
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync} RTLOCKVALCLASSINT;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncAssertCompileSize(AVLLU32NODECORE, ARCH_BITS == 32 ? 20 : 32);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncAssertCompileMemberOffset(RTLOCKVALCLASSINT, PriorLocks, 64);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/*******************************************************************************
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync* Global Variables *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync*******************************************************************************/
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** Serializing object destruction and deadlock detection.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * This makes sure that none of the memory examined by the deadlock detection
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * code will become invalid (reused for other purposes or made not present)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * while the detection is in progress.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * NS: RTLOCKVALREC*, RTTHREADINT and RTLOCKVALDRECSHRD::papOwners destruction.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * EW: Deadlock detection and some related activities.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic RTSEMXROADS g_hLockValidatorXRoads = NIL_RTSEMXROADS;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** Serializing class tree insert and lookups. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic RTSEMRW g_hLockValClassTreeRWLock= NIL_RTSEMRW;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** Class tree. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic PAVLLU32NODECORE g_LockValClassTree = NULL;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** Critical section serializing the teaching new rules to the classes. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic RTCRITSECT g_LockValClassTeachCS;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** Whether the lock validator is enabled or disabled.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Only applies to new locks. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic bool volatile g_fLockValidatorEnabled = true;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** Set if the lock validator is quiet. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#ifdef RT_STRICT
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic bool volatile g_fLockValidatorQuiet = false;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#else
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic bool volatile g_fLockValidatorQuiet = true;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#endif
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** Set if the lock validator may panic. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#ifdef RT_STRICT
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic bool volatile g_fLockValidatorMayPanic = true;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#else
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic bool volatile g_fLockValidatorMayPanic = false;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#endif
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** Whether to return an error status on wrong locking order. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic bool volatile g_fLockValSoftWrongOrder = false;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/*******************************************************************************
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync* Internal Functions *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync*******************************************************************************/
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic void rtLockValidatorClassDestroy(RTLOCKVALCLASSINT *pClass);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic uint32_t rtLockValidatorStackDepth(PRTTHREADINT pThread);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/**
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Lazy initialization of the lock validator globals.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic void rtLockValidatorLazyInit(void)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync static uint32_t volatile s_fInitializing = false;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (ASMAtomicCmpXchgU32(&s_fInitializing, true, false))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /*
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * The locks.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (!RTCritSectIsInitialized(&g_LockValClassTeachCS))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTCritSectInitEx(&g_LockValClassTeachCS, RTCRITSECT_FLAGS_NO_LOCK_VAL, NIL_RTLOCKVALCLASS,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTLOCKVAL_SUB_CLASS_ANY, "RTLockVal-Teach");
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (g_hLockValClassTreeRWLock == NIL_RTSEMRW)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTSEMRW hSemRW;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync int rc = RTSemRWCreateEx(&hSemRW, RTSEMRW_FLAGS_NO_LOCK_VAL, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_ANY, "RTLockVal-Tree");
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (RT_SUCCESS(rc))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteHandle(&g_hLockValClassTreeRWLock, hSemRW);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (g_hLockValidatorXRoads == NIL_RTSEMXROADS)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTSEMXROADS hXRoads;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync int rc = RTSemXRoadsCreate(&hXRoads);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (RT_SUCCESS(rc))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteHandle(&g_hLockValidatorXRoads, hXRoads);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#ifdef IN_RING3
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /*
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Check the environment for our config variables.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (RTEnvExist("IPRT_LOCK_VALIDATOR_ENABLED"))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteBool(&g_fLockValidatorEnabled, true);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (RTEnvExist("IPRT_LOCK_VALIDATOR_DISABLED"))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteBool(&g_fLockValidatorEnabled, false);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (RTEnvExist("IPRT_LOCK_VALIDATOR_MAY_PANIC"))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteBool(&g_fLockValidatorMayPanic, true);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (RTEnvExist("IPRT_LOCK_VALIDATOR_MAY_NOT_PANIC"))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteBool(&g_fLockValidatorMayPanic, false);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (RTEnvExist("IPRT_LOCK_VALIDATOR_NOT_QUIET"))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteBool(&g_fLockValidatorQuiet, false);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (RTEnvExist("IPRT_LOCK_VALIDATOR_QUIET"))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteBool(&g_fLockValidatorQuiet, true);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (RTEnvExist("IPRT_LOCK_VALIDATOR_STRICT_ORDER"))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteBool(&g_fLockValSoftWrongOrder, false);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (RTEnvExist("IPRT_LOCK_VALIDATOR_SOFT_ORDER"))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteBool(&g_fLockValSoftWrongOrder, true);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#endif
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /*
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Register cleanup
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** @todo register some cleanup callback if we care. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteU32(&s_fInitializing, false);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** Wrapper around ASMAtomicReadPtr. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncDECL_FORCE_INLINE(PRTLOCKVALRECUNION) rtLockValidatorReadRecUnionPtr(PRTLOCKVALRECUNION volatile *ppRec)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTLOCKVALRECUNION p = ASMAtomicReadPtrT(ppRec, PRTLOCKVALRECUNION);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTLOCKVAL_ASSERT_PTR_ALIGN(p);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return p;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** Wrapper around ASMAtomicWritePtr. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncDECL_FORCE_INLINE(void) rtLockValidatorWriteRecUnionPtr(PRTLOCKVALRECUNION volatile *ppRec, PRTLOCKVALRECUNION pRecNew)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTLOCKVAL_ASSERT_PTR_ALIGN(pRecNew);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWritePtr(ppRec, pRecNew);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** Wrapper around ASMAtomicReadPtr. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncDECL_FORCE_INLINE(PRTTHREADINT) rtLockValidatorReadThreadHandle(RTTHREAD volatile *phThread)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTTHREADINT p = ASMAtomicReadPtrT(phThread, PRTTHREADINT);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTLOCKVAL_ASSERT_PTR_ALIGN(p);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return p;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** Wrapper around ASMAtomicUoReadPtr. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncDECL_FORCE_INLINE(PRTLOCKVALRECSHRDOWN) rtLockValidatorUoReadSharedOwner(PRTLOCKVALRECSHRDOWN volatile *ppOwner)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTLOCKVALRECSHRDOWN p = ASMAtomicUoReadPtrT(ppOwner, PRTLOCKVALRECSHRDOWN);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTLOCKVAL_ASSERT_PTR_ALIGN(p);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return p;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/**
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Reads a volatile thread handle field and returns the thread name.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @returns Thread name (read only).
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param phThread The thread handle field.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic const char *rtLockValidatorNameThreadHandle(RTTHREAD volatile *phThread)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTTHREADINT pThread = rtLockValidatorReadThreadHandle(phThread);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (!pThread)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return "<NIL>";
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (!VALID_PTR(pThread))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return "<INVALID>";
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (pThread->u32Magic != RTTHREADINT_MAGIC)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return "<BAD-THREAD-MAGIC>";
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return pThread->szName;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/**
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Launch a simple assertion like complaint w/ panic.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pszFile Where from - file.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param iLine Where from - line.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pszFunction Where from - function.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pszWhat What we're complaining about.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param ... Format arguments.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic void rtLockValComplain(RT_SRC_POS_DECL, const char *pszWhat, ...)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (!ASMAtomicUoReadBool(&g_fLockValidatorQuiet))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTAssertMsg1Weak("RTLockValidator", iLine, pszFile, pszFunction);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync va_list va;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync va_start(va, pszWhat);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTAssertMsg2WeakV(pszWhat, va);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync va_end(va);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (!ASMAtomicUoReadBool(&g_fLockValidatorQuiet))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTAssertPanic();
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/**
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Describes the class.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pszPrefix Message prefix.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pClass The class to complain about.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param uSubClass My sub-class.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param fVerbose Verbose description including relations to other
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * classes.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic void rtLockValComplainAboutClass(const char *pszPrefix, RTLOCKVALCLASSINT *pClass, uint32_t uSubClass, bool fVerbose)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (ASMAtomicUoReadBool(&g_fLockValidatorQuiet))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /* Stringify the sub-class. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync const char *pszSubClass;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync char szSubClass[32];
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (uSubClass < RTLOCKVAL_SUB_CLASS_USER)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync switch (uSubClass)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync case RTLOCKVAL_SUB_CLASS_NONE: pszSubClass = "none"; break;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync case RTLOCKVAL_SUB_CLASS_ANY: pszSubClass = "any"; break;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync default:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTStrPrintf(szSubClass, sizeof(szSubClass), "invl-%u", uSubClass);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pszSubClass = szSubClass;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync break;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync else
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTStrPrintf(szSubClass, sizeof(szSubClass), "%u", uSubClass);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pszSubClass = szSubClass;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /* Validate the class pointer. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (!VALID_PTR(pClass))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTAssertMsg2AddWeak("%sbad class=%p sub-class=%s\n", pszPrefix, pClass, pszSubClass);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (pClass->u32Magic != RTLOCKVALCLASS_MAGIC)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTAssertMsg2AddWeak("%sbad class=%p magic=%#x sub-class=%s\n", pszPrefix, pClass, pClass->u32Magic, pszSubClass);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /* OK, dump the class info. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTAssertMsg2AddWeak("%sclass=%p %s created={%Rbn(%u) %Rfn %p} sub-class=%s\n", pszPrefix,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pClass,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pClass->pszName,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pClass->CreatePos.pszFile,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pClass->CreatePos.uLine,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pClass->CreatePos.pszFunction,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pClass->CreatePos.uId,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pszSubClass);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (fVerbose)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync uint32_t i = 0;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync uint32_t cPrinted = 0;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync for (PRTLOCKVALCLASSREFCHUNK pChunk = &pClass->PriorLocks; pChunk; pChunk = pChunk->pNext)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync for (unsigned j = 0; j < RT_ELEMENTS(pChunk->aRefs); j++, i++)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTLOCKVALCLASSINT *pCurClass = pChunk->aRefs[j].hClass;
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync if (pCurClass != NIL_RTLOCKVALCLASS)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTAssertMsg2AddWeak("%s%s #%02u: %s, %s, %u lookup%s\n", pszPrefix,
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync cPrinted == 0
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync ? "Prior:"
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync : " ",
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync i,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pCurClass->pszName,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pChunk->aRefs[j].fAutodidacticism
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync ? "autodidactic"
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync : "manually ",
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync pChunk->aRefs[j].cLookups,
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync pChunk->aRefs[j].cLookups != 1 ? "s" : "");
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync cPrinted++;
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync }
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync }
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync if (!cPrinted)
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync RTAssertMsg2AddWeak("%sPrior: none\n", pszPrefix);
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync#ifdef RTLOCKVAL_WITH_CLASS_HASH_STATS
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync RTAssertMsg2AddWeak("%sHash Stats: %u hits, %u misses\n", pszPrefix, pClass->cHashHits, pClass->cHashMisses);
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync#endif
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync }
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync else
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync uint32_t cPrinted = 0;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync for (PRTLOCKVALCLASSREFCHUNK pChunk = &pClass->PriorLocks; pChunk; pChunk = pChunk->pNext)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync for (unsigned j = 0; j < RT_ELEMENTS(pChunk->aRefs); j++)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTLOCKVALCLASSINT *pCurClass = pChunk->aRefs[j].hClass;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (pCurClass != NIL_RTLOCKVALCLASS)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if ((cPrinted % 10) == 0)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTAssertMsg2AddWeak("%sPrior classes: %s%s", pszPrefix, pCurClass->pszName,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pChunk->aRefs[j].fAutodidacticism ? "*" : "");
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync else if ((cPrinted % 10) != 9)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTAssertMsg2AddWeak(", %s%s", pCurClass->pszName,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pChunk->aRefs[j].fAutodidacticism ? "*" : "");
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync else
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTAssertMsg2AddWeak(", %s%s\n", pCurClass->pszName,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pChunk->aRefs[j].fAutodidacticism ? "*" : "");
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync cPrinted++;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (!cPrinted)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTAssertMsg2AddWeak("%sPrior classes: none\n", pszPrefix);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync else if ((cPrinted % 10) != 0)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTAssertMsg2AddWeak("\n");
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/**
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Helper for getting the class name.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @returns Class name string.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pClass The class.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic const char *rtLockValComplainGetClassName(RTLOCKVALCLASSINT *pClass)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync if (!pClass)
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync return "<nil-class>";
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync if (!VALID_PTR(pClass))
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync return "<bad-class-ptr>";
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync if (pClass->u32Magic != RTLOCKVALCLASS_MAGIC)
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync return "<bad-class-magic>";
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync if (!pClass->pszName)
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync return "<no-class-name>";
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync return pClass->pszName;
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync}
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync/**
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync * Formats the sub-class.
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync *
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync * @returns Stringified sub-class.
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync * @param uSubClass The name.
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync * @param pszBuf Buffer that is big enough.
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync */
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsyncstatic const char *rtLockValComplainGetSubClassName(uint32_t uSubClass, char *pszBuf)
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync{
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync if (uSubClass < RTLOCKVAL_SUB_CLASS_USER)
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync switch (uSubClass)
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync {
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync case RTLOCKVAL_SUB_CLASS_NONE: return "none";
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync case RTLOCKVAL_SUB_CLASS_ANY: return "any";
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync default:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTStrPrintf(pszBuf, 32, "invl-%u", uSubClass);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync break;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync else
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTStrPrintf(pszBuf, 32, "%x", uSubClass);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return pszBuf;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/**
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Helper for rtLockValComplainAboutLock.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncDECL_FORCE_INLINE(void) rtLockValComplainAboutLockHlp(const char *pszPrefix, PRTLOCKVALRECUNION pRec, const char *pszSuffix,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync uint32_t u32Magic, PCRTLOCKVALSRCPOS pSrcPos, uint32_t cRecursion,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync const char *pszFrameType)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync char szBuf[32];
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync switch (u32Magic)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync case RTLOCKVALRECEXCL_MAGIC:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#ifdef RTLOCKVAL_WITH_VERBOSE_DUMPS
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTAssertMsg2AddWeak("%s%p %s xrec=%p own=%s r=%u cls=%s/%s pos={%Rbn(%u) %Rfn %p} [x%s]%s", pszPrefix,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pRec->Excl.hLock, pRec->Excl.pszName, pRec,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rtLockValidatorNameThreadHandle(&pRec->Excl.hThread), cRecursion,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rtLockValComplainGetClassName(pRec->Excl.hClass),
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rtLockValComplainGetSubClassName(pRec->Excl.uSubClass, szBuf),
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pSrcPos->pszFile, pSrcPos->uLine, pSrcPos->pszFunction, pSrcPos->uId,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pszFrameType, pszSuffix);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#else
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTAssertMsg2AddWeak("%s%p %s own=%s r=%u cls=%s/%s pos={%Rbn(%u) %Rfn %p} [x%s]%s", pszPrefix,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pRec->Excl.hLock, pRec->Excl.szName,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rtLockValidatorNameThreadHandle(&pRec->Excl.hThread), cRecursion,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rtLockValComplainGetClassName(pRec->Excl.hClass),
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rtLockValComplainGetSubClassName(pRec->Excl.uSubClass, szBuf),
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pSrcPos->pszFile, pSrcPos->uLine, pSrcPos->pszFunction, pSrcPos->uId,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pszFrameType, pszSuffix);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#endif
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync break;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync case RTLOCKVALRECSHRD_MAGIC:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTAssertMsg2AddWeak("%ss %p %s srec=%p cls=%s/%s [s%s]%s", pszPrefix,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pRec->Shared.hLock, pRec->Shared.szName, pRec,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rtLockValComplainGetClassName(pRec->Shared.hClass),
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rtLockValComplainGetSubClassName(pRec->Shared.uSubClass, szBuf),
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pszFrameType, pszSuffix);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync break;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync case RTLOCKVALRECSHRDOWN_MAGIC:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTLOCKVALRECSHRD pShared = pRec->ShrdOwner.pSharedRec;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if ( VALID_PTR(pShared)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync && pShared->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#ifdef RTLOCKVAL_WITH_VERBOSE_DUMPS
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTAssertMsg2AddWeak("%s%p %s srec=%p trec=%p own=%s r=%u cls=%s/%s pos={%Rbn(%u) %Rfn %p} [o%s]%s", pszPrefix,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pShared->hLock, pShared->pszName, pShared,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pRec, rtLockValidatorNameThreadHandle(&pRec->ShrdOwner.hThread), cRecursion,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync rtLockValComplainGetClassName(pShared->hClass),
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync rtLockValComplainGetSubClassName(pShared->uSubClass, szBuf),
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pSrcPos->pszFile, pSrcPos->uLine, pSrcPos->pszFunction, pSrcPos->uId,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pszSuffix2, pszSuffix);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync#else
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync RTAssertMsg2AddWeak("%s%p %s own=%s r=%u cls=%s/%s pos={%Rbn(%u) %Rfn %p} [o%s]%s", pszPrefix,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pShared->hLock, pShared->szName,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync rtLockValidatorNameThreadHandle(&pRec->ShrdOwner.hThread), cRecursion,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync rtLockValComplainGetClassName(pShared->hClass),
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync rtLockValComplainGetSubClassName(pShared->uSubClass, szBuf),
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pSrcPos->pszFile, pSrcPos->uLine, pSrcPos->pszFunction, pSrcPos->uId,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pszFrameType, pszSuffix);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync#endif
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync else
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync RTAssertMsg2AddWeak("%sbad srec=%p trec=%p own=%s r=%u pos={%Rbn(%u) %Rfn %p} [x%s]%s", pszPrefix,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pShared,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pRec, rtLockValidatorNameThreadHandle(&pRec->ShrdOwner.hThread), cRecursion,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pSrcPos->pszFile, pSrcPos->uLine, pSrcPos->pszFunction, pSrcPos->uId,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pszFrameType, pszSuffix);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync break;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync }
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync default:
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync AssertMsgFailed(("%#x\n", u32Magic));
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync }
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync}
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync/**
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * Describes the lock.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync *
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @param pszPrefix Message prefix.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @param pRec The lock record we're working on.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @param pszSuffix Message suffix.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync */
6e7c344fc7cdb580356704e8201207b394d367bbvboxsyncstatic void rtLockValComplainAboutLock(const char *pszPrefix, PRTLOCKVALRECUNION pRec, const char *pszSuffix)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync{
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync#ifdef RTLOCKVAL_WITH_RECURSION_RECORDS
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync# define FIX_REC(r) 1
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync#else
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync# define FIX_REC(r) (r)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync#endif
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync if ( VALID_PTR(pRec)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync && !ASMAtomicUoReadBool(&g_fLockValidatorQuiet))
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync {
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync switch (pRec->Core.u32Magic)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync {
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync case RTLOCKVALRECEXCL_MAGIC:
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync rtLockValComplainAboutLockHlp(pszPrefix, pRec, pszSuffix, RTLOCKVALRECEXCL_MAGIC,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync &pRec->Excl.SrcPos, FIX_REC(pRec->Excl.cRecursion), "");
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync break;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync case RTLOCKVALRECSHRD_MAGIC:
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync rtLockValComplainAboutLockHlp(pszPrefix, pRec, pszSuffix, RTLOCKVALRECSHRD_MAGIC, NULL, 0, "");
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync break;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync case RTLOCKVALRECSHRDOWN_MAGIC:
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync rtLockValComplainAboutLockHlp(pszPrefix, pRec, pszSuffix, RTLOCKVALRECSHRDOWN_MAGIC,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync &pRec->ShrdOwner.SrcPos, FIX_REC(pRec->ShrdOwner.cRecursion), "");
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync break;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync case RTLOCKVALRECNEST_MAGIC:
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync {
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync PRTLOCKVALRECUNION pRealRec = pRec->Nest.pRec;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync uint32_t u32Magic;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync if ( VALID_PTR(pRealRec)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync && ( (u32Magic = pRealRec->Core.u32Magic) == RTLOCKVALRECEXCL_MAGIC
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync || u32Magic == RTLOCKVALRECSHRD_MAGIC
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync || u32Magic == RTLOCKVALRECSHRDOWN_MAGIC)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync )
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync rtLockValComplainAboutLockHlp(pszPrefix, pRealRec, pszSuffix, u32Magic,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync &pRec->Nest.SrcPos, pRec->Nest.cRecursion, "/r");
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync else
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync RTAssertMsg2AddWeak("%sbad rrec=%p nrec=%p r=%u pos={%Rbn(%u) %Rfn %p}%s", pszPrefix,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pRealRec, pRec, pRec->Nest.cRecursion,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pRec->Nest.SrcPos.pszFile, pRec->Nest.SrcPos.uLine, pRec->Nest.SrcPos.pszFunction, pRec->Nest.SrcPos.uId,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pszSuffix);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync break;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync }
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync default:
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync RTAssertMsg2AddWeak("%spRec=%p u32Magic=%#x (bad)%s", pszPrefix, pRec, pRec->Core.u32Magic, pszSuffix);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync break;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync }
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync }
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync#undef FIX_REC
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync}
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync/**
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * Dump the lock stack.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync *
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @param pThread The thread which lock stack we're gonna dump.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @param cchIndent The indentation in chars.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @param cMinFrames The minimum number of frames to consider
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * dumping.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @param pHighightRec Record that should be marked specially in the
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * dump.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync */
6e7c344fc7cdb580356704e8201207b394d367bbvboxsyncstatic void rtLockValComplainAboutLockStack(PRTTHREADINT pThread, unsigned cchIndent, uint32_t cMinFrames,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync PRTLOCKVALRECUNION pHighightRec)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync{
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync if ( VALID_PTR(pThread)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync && !ASMAtomicUoReadBool(&g_fLockValidatorQuiet)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync && pThread->u32Magic == RTTHREADINT_MAGIC
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync )
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync {
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync uint32_t cEntries = rtLockValidatorStackDepth(pThread);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync if (cEntries >= cMinFrames)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync {
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync RTAssertMsg2AddWeak("%*s---- start of lock stack for %p %s - %u entr%s ----\n", cchIndent, "",
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pThread, pThread->szName, cEntries, cEntries == 1 ? "y" : "ies");
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync PRTLOCKVALRECUNION pCur = rtLockValidatorReadRecUnionPtr(&pThread->LockValidator.pStackTop);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync for (uint32_t i = 0; VALID_PTR(pCur); i++)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync {
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync char szPrefix[80];
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync RTStrPrintf(szPrefix, sizeof(szPrefix), "%*s#%02u: ", cchIndent, "", i);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync rtLockValComplainAboutLock(szPrefix, pCur, pHighightRec != pCur ? "\n" : " (*)\n");
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync switch (pCur->Core.u32Magic)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync {
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync case RTLOCKVALRECEXCL_MAGIC: pCur = rtLockValidatorReadRecUnionPtr(&pCur->Excl.pDown); break;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync case RTLOCKVALRECSHRDOWN_MAGIC: pCur = rtLockValidatorReadRecUnionPtr(&pCur->ShrdOwner.pDown); break;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync case RTLOCKVALRECNEST_MAGIC: pCur = rtLockValidatorReadRecUnionPtr(&pCur->Nest.pDown); break;
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync default:
841fc232dfd102207563580ef5b2875edb98e305vboxsync RTAssertMsg2AddWeak("%*s<bad stack frame>\n", cchIndent, "");
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync pCur = NULL;
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync break;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync }
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync }
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync RTAssertMsg2AddWeak("%*s---- end of lock stack ----\n", cchIndent, "");
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync }
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync }
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync}
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync/**
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * Launch the initial complaint.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync *
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @param pszWhat What we're complaining about.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @param pSrcPos Where we are complaining from, as it were.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @param pThreadSelf The calling thread.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @param pRec The main lock involved. Can be NULL.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @param fDumpStack Whether to dump the lock stack (true) or not
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * (false).
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync */
6e7c344fc7cdb580356704e8201207b394d367bbvboxsyncstatic void rtLockValComplainFirst(const char *pszWhat, PCRTLOCKVALSRCPOS pSrcPos, PRTTHREADINT pThreadSelf,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync PRTLOCKVALRECUNION pRec, bool fDumpStack)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync{
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync if (!ASMAtomicUoReadBool(&g_fLockValidatorQuiet))
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync {
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync ASMCompilerBarrier(); /* paranoia */
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync RTAssertMsg1Weak("RTLockValidator", pSrcPos ? pSrcPos->uLine : 0, pSrcPos ? pSrcPos->pszFile : NULL, pSrcPos ? pSrcPos->pszFunction : NULL);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync if (pSrcPos && pSrcPos->uId)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync RTAssertMsg2Weak("%s [uId=%p thrd=%s]\n", pszWhat, pSrcPos->uId, VALID_PTR(pThreadSelf) ? pThreadSelf->szName : "<NIL>");
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync else
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync RTAssertMsg2Weak("%s [thrd=%s]\n", pszWhat, VALID_PTR(pThreadSelf) ? pThreadSelf->szName : "<NIL>");
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync rtLockValComplainAboutLock("Lock: ", pRec, "\n");
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync if (fDumpStack)
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync rtLockValComplainAboutLockStack(pThreadSelf, 0, 1, pRec);
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync }
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync}
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync/**
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync * Continue bitching.
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync *
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync * @param pszFormat Format string.
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync * @param ... Format arguments.
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync */
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsyncstatic void rtLockValComplainMore(const char *pszFormat, ...)
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync{
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync if (!ASMAtomicUoReadBool(&g_fLockValidatorQuiet))
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync {
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync va_list va;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync va_start(va, pszFormat);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync RTAssertMsg2AddWeakV(pszFormat, va);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync va_end(va);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync }
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync}
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync/**
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * Raise a panic if enabled.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync */
6e7c344fc7cdb580356704e8201207b394d367bbvboxsyncstatic void rtLockValComplainPanic(void)
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync{
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync if (ASMAtomicUoReadBool(&g_fLockValidatorMayPanic))
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync RTAssertPanic();
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync}
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync/**
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * Copy a source position record.
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync *
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync * @param pDst The destination.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @param pSrc The source. Can be NULL.
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync */
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsyncDECL_FORCE_INLINE(void) rtLockValidatorSrcPosCopy(PRTLOCKVALSRCPOS pDst, PCRTLOCKVALSRCPOS pSrc)
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync{
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync if (pSrc)
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync {
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync ASMAtomicUoWriteU32(&pDst->uLine, pSrc->uLine);
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync ASMAtomicUoWritePtr(&pDst->pszFile, pSrc->pszFile);
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync ASMAtomicUoWritePtr(&pDst->pszFunction, pSrc->pszFunction);
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync ASMAtomicUoWritePtr((void * volatile *)&pDst->uId, (void *)pSrc->uId);
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync }
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync else
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync {
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync ASMAtomicUoWriteU32(&pDst->uLine, 0);
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync ASMAtomicUoWriteNullPtr(&pDst->pszFile);
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync ASMAtomicUoWriteNullPtr(&pDst->pszFunction);
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync ASMAtomicUoWritePtr(&pDst->uId, (RTHCUINTPTR)0);
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync }
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync}
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync/**
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync * Init a source position record.
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync *
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync * @param pSrcPos The source position record.
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync */
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsyncDECL_FORCE_INLINE(void) rtLockValidatorSrcPosInit(PRTLOCKVALSRCPOS pSrcPos)
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync{
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pSrcPos->pszFile = NULL;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pSrcPos->pszFunction = NULL;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pSrcPos->uId = 0;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pSrcPos->uLine = 0;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync#if HC_ARCH_BITS == 64
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pSrcPos->u32Padding = 0;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync#endif
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync}
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync/**
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync * Hashes the specified source position.
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync *
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync * @returns Hash.
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync * @param pSrcPos The source position record.
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync */
e42c49edebbc79edb6d87377bab6d879fdb602favboxsyncstatic uint32_t rtLockValidatorSrcPosHash(PCRTLOCKVALSRCPOS pSrcPos)
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync{
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync uint32_t uHash;
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync if ( ( pSrcPos->pszFile
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync || pSrcPos->pszFunction)
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync && pSrcPos->uLine != 0)
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync {
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync uHash = 0;
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync if (pSrcPos->pszFile)
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync uHash = sdbmInc(pSrcPos->pszFile, uHash);
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync if (pSrcPos->pszFunction)
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync uHash = sdbmInc(pSrcPos->pszFunction, uHash);
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync uHash += pSrcPos->uLine;
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync }
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync else
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync {
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync Assert(pSrcPos->uId);
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync uHash = (uint32_t)pSrcPos->uId;
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync }
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync return uHash;
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync}
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync/**
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync * Compares two source positions.
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync *
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync * @returns 0 if equal, < 0 if pSrcPos1 is smaller than pSrcPos2, > 0 if
d28dc67f08822d73f954174fab43e570131b54davboxsync * otherwise.
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync * @param pSrcPos1 The first source position.
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync * @param pSrcPos2 The second source position.
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync */
e42c49edebbc79edb6d87377bab6d879fdb602favboxsyncstatic int rtLockValidatorSrcPosCompare(PCRTLOCKVALSRCPOS pSrcPos1, PCRTLOCKVALSRCPOS pSrcPos2)
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync{
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync if (pSrcPos1->uLine != pSrcPos2->uLine)
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync return pSrcPos1->uLine < pSrcPos2->uLine ? -1 : 1;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync int iDiff = RTStrCmp(pSrcPos1->pszFile, pSrcPos2->pszFile);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync if (iDiff != 0)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync return iDiff;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync iDiff = RTStrCmp(pSrcPos1->pszFunction, pSrcPos2->pszFunction);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync if (iDiff != 0)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync return iDiff;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync if (pSrcPos1->uId != pSrcPos2->uId)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync return pSrcPos1->uId < pSrcPos2->uId ? -1 : 1;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync return 0;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync}
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync/**
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Serializes destruction of RTLOCKVALREC* and RTTHREADINT structures.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsyncDECLHIDDEN(void) rtLockValidatorSerializeDestructEnter(void)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync{
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync RTSEMXROADS hXRoads = g_hLockValidatorXRoads;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync if (hXRoads != NIL_RTSEMXROADS)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync RTSemXRoadsNSEnter(hXRoads);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync}
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync/**
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Call after rtLockValidatorSerializeDestructEnter.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsyncDECLHIDDEN(void) rtLockValidatorSerializeDestructLeave(void)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync{
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync RTSEMXROADS hXRoads = g_hLockValidatorXRoads;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync if (hXRoads != NIL_RTSEMXROADS)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync RTSemXRoadsNSLeave(hXRoads);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync}
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync/**
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Serializes deadlock detection against destruction of the objects being
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * inspected.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsyncDECLINLINE(void) rtLockValidatorSerializeDetectionEnter(void)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync{
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync RTSEMXROADS hXRoads = g_hLockValidatorXRoads;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync if (hXRoads != NIL_RTSEMXROADS)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync RTSemXRoadsEWEnter(hXRoads);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync}
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync/**
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Call after rtLockValidatorSerializeDetectionEnter.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsyncDECLHIDDEN(void) rtLockValidatorSerializeDetectionLeave(void)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync{
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync RTSEMXROADS hXRoads = g_hLockValidatorXRoads;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync if (hXRoads != NIL_RTSEMXROADS)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync RTSemXRoadsEWLeave(hXRoads);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync}
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync/**
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Initializes the per thread lock validator data.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync *
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * @param pPerThread The data.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsyncDECLHIDDEN(void) rtLockValidatorInitPerThread(RTLOCKVALPERTHREAD *pPerThread)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync{
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pPerThread->bmFreeShrdOwners = UINT32_MAX;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync /* ASSUMES the rest has already been zeroed. */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync Assert(pPerThread->pRec == NULL);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync Assert(pPerThread->cWriteLocks == 0);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync Assert(pPerThread->cReadLocks == 0);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync Assert(pPerThread->fInValidator == false);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync Assert(pPerThread->pStackTop == NULL);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync}
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync/**
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Delete the per thread lock validator data.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync *
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * @param pPerThread The data.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsyncDECLHIDDEN(void) rtLockValidatorDeletePerThread(RTLOCKVALPERTHREAD *pPerThread)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync{
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync /*
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Check that the thread doesn't own any locks at this time.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync if (pPerThread->pStackTop)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync {
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValComplainFirst("Thread terminating owning locks!", NULL,
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync RT_FROM_MEMBER(pPerThread, RTTHREADINT, LockValidator),
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pPerThread->pStackTop, true);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValComplainPanic();
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync }
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync /*
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Free the recursion records.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync PRTLOCKVALRECNEST pCur = pPerThread->pFreeNestRecs;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pPerThread->pFreeNestRecs = NULL;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync while (pCur)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync {
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync PRTLOCKVALRECNEST pNext = pCur->pNextFree;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync RTMemFree(pCur);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pCur = pNext;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync }
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync}
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsyncRTDECL(int) RTLockValidatorClassCreateEx(PRTLOCKVALCLASS phClass, PCRTLOCKVALSRCPOS pSrcPos,
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync bool fAutodidact, bool fRecursionOk, bool fStrictReleaseOrder,
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync RTMSINTERVAL cMsMinDeadlock, RTMSINTERVAL cMsMinOrder,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync const char *pszNameFmt, ...)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync va_list va;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync va_start(va, pszNameFmt);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync int rc = RTLockValidatorClassCreateExV(phClass, pSrcPos, fAutodidact, fRecursionOk, fStrictReleaseOrder,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync cMsMinDeadlock, cMsMinOrder, pszNameFmt, va);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync va_end(va);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return rc;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncRTDECL(int) RTLockValidatorClassCreateExV(PRTLOCKVALCLASS phClass, PCRTLOCKVALSRCPOS pSrcPos,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync bool fAutodidact, bool fRecursionOk, bool fStrictReleaseOrder,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTMSINTERVAL cMsMinDeadlock, RTMSINTERVAL cMsMinOrder,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync const char *pszNameFmt, va_list va)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync Assert(cMsMinDeadlock >= 1);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync Assert(cMsMinOrder >= 1);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertPtr(pSrcPos);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /*
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Format the name and calc its length.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync size_t cbName;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync char szName[32];
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (pszNameFmt && *pszNameFmt)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync cbName = RTStrPrintfV(szName, sizeof(szName), pszNameFmt, va) + 1;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync else
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync static uint32_t volatile s_cAnonymous = 0;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync uint32_t i = ASMAtomicIncU32(&s_cAnonymous);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync cbName = RTStrPrintf(szName, sizeof(szName), "anon-%u", i - 1) + 1;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /*
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Figure out the file and function name lengths and allocate memory for
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * it all.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync size_t const cbFile = pSrcPos->pszFile ? strlen(pSrcPos->pszFile) + 1 : 0;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync size_t const cbFunction = pSrcPos->pszFile ? strlen(pSrcPos->pszFunction) + 1 : 0;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTLOCKVALCLASSINT *pThis = (RTLOCKVALCLASSINT *)RTMemAllocVar(sizeof(*pThis) + cbFile + cbFunction + cbName);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (!pThis)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return VERR_NO_MEMORY;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /*
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Initialize the class data.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pThis->Core.Key = rtLockValidatorSrcPosHash(pSrcPos);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pThis->Core.uchHeight = 0;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pThis->Core.pLeft = NULL;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pThis->Core.pRight = NULL;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pThis->Core.pList = NULL;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pThis->u32Magic = RTLOCKVALCLASS_MAGIC;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pThis->cRefs = 1;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pThis->fAutodidact = fAutodidact;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pThis->fRecursionOk = fRecursionOk;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pThis->fStrictReleaseOrder = fStrictReleaseOrder;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pThis->fInTree = false;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pThis->fDonateRefToNextRetainer = false;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pThis->afReserved[0] = false;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pThis->afReserved[1] = false;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pThis->afReserved[2] = false;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pThis->cMsMinDeadlock = cMsMinDeadlock;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pThis->cMsMinOrder = cMsMinOrder;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync for (unsigned i = 0; i < RT_ELEMENTS(pThis->au32Reserved); i++)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pThis->au32Reserved[i] = 0;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync for (unsigned i = 0; i < RT_ELEMENTS(pThis->PriorLocks.aRefs); i++)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pThis->PriorLocks.aRefs[i].hClass = NIL_RTLOCKVALCLASS;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pThis->PriorLocks.aRefs[i].cLookups = 0;
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync pThis->PriorLocks.aRefs[i].fAutodidacticism = false;
f8220bb50249140c67ecb7267e9870ee19ca159fvboxsync pThis->PriorLocks.aRefs[i].afReserved[0] = false;
f8220bb50249140c67ecb7267e9870ee19ca159fvboxsync pThis->PriorLocks.aRefs[i].afReserved[1] = false;
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync pThis->PriorLocks.aRefs[i].afReserved[2] = false;
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync }
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync pThis->PriorLocks.pNext = NULL;
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync for (unsigned i = 0; i < RT_ELEMENTS(pThis->apPriorLocksHash); i++)
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync pThis->apPriorLocksHash[i] = NULL;
f8220bb50249140c67ecb7267e9870ee19ca159fvboxsync char *pszDst = (char *)(pThis + 1);
f8220bb50249140c67ecb7267e9870ee19ca159fvboxsync pThis->pszName = (char *)memcpy(pszDst, szName, cbName);
f8220bb50249140c67ecb7267e9870ee19ca159fvboxsync pszDst += cbName;
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync rtLockValidatorSrcPosCopy(&pThis->CreatePos, pSrcPos);
f8220bb50249140c67ecb7267e9870ee19ca159fvboxsync pThis->CreatePos.pszFile = pSrcPos->pszFile ? (char *)memcpy(pszDst, pSrcPos->pszFile, cbFile) : NULL;
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync pszDst += cbFile;
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync pThis->CreatePos.pszFunction= pSrcPos->pszFunction ? (char *)memcpy(pszDst, pSrcPos->pszFunction, cbFunction) : NULL;
f8220bb50249140c67ecb7267e9870ee19ca159fvboxsync Assert(rtLockValidatorSrcPosHash(&pThis->CreatePos) == pThis->Core.Key);
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync#ifdef RTLOCKVAL_WITH_CLASS_HASH_STATS
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync pThis->cHashHits = 0;
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync pThis->cHashMisses = 0;
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync#endif
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *phClass = pThis;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return VINF_SUCCESS;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncRTDECL(int) RTLockValidatorClassCreate(PRTLOCKVALCLASS phClass, bool fAutodidact, RT_SRC_POS_DECL, const char *pszNameFmt, ...)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_POS_NO_ID();
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync va_list va;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync va_start(va, pszNameFmt);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync int rc = RTLockValidatorClassCreateExV(phClass, &SrcPos,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync fAutodidact, true /*fRecursionOk*/, false /*fStrictReleaseOrder*/,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync 1 /*cMsMinDeadlock*/, 1 /*cMsMinOrder*/,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pszNameFmt, va);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync va_end(va);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return rc;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/**
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Creates a new lock validator class with a reference that is consumed by the
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * first call to RTLockValidatorClassRetain.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * This is tailored for use in the parameter list of a semaphore constructor.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @returns Class handle with a reference that is automatically consumed by the
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * first retainer. NIL_RTLOCKVALCLASS if we run into trouble.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pszFile The source position of the call, file.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param iLine The source position of the call, line.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pszFunction The source position of the call, function.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pszNameFmt Class name format string, optional (NULL). Max
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * length is 32 bytes.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param ... Format string arguments.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncRTDECL(RTLOCKVALCLASS) RTLockValidatorClassCreateUnique(RT_SRC_POS_DECL, const char *pszNameFmt, ...)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_POS_NO_ID();
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTLOCKVALCLASSINT *pClass;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync va_list va;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync va_start(va, pszNameFmt);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync int rc = RTLockValidatorClassCreateExV(&pClass, &SrcPos,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync true /*fAutodidact*/, true /*fRecursionOk*/, false /*fStrictReleaseOrder*/,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync 1 /*cMsMinDeadlock*/, 1 /*cMsMinOrder*/,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pszNameFmt, va);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync va_end(va);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (RT_FAILURE(rc))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return NIL_RTLOCKVALCLASS;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteBool(&pClass->fDonateRefToNextRetainer, true); /* see rtLockValidatorClassRetain */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return pClass;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/**
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Internal class retainer.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @returns The new reference count.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pClass The class.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncDECL_FORCE_INLINE(uint32_t) rtLockValidatorClassRetain(RTLOCKVALCLASSINT *pClass)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync uint32_t cRefs = ASMAtomicIncU32(&pClass->cRefs);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (cRefs > RTLOCKVALCLASS_MAX_REFS)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteU32(&pClass->cRefs, RTLOCKVALCLASS_MAX_REFS);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync else if ( cRefs == 2
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync && ASMAtomicXchgBool(&pClass->fDonateRefToNextRetainer, false))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync cRefs = ASMAtomicDecU32(&pClass->cRefs);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return cRefs;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/**
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Validates and retains a lock validator class.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @returns @a hClass on success, NIL_RTLOCKVALCLASS on failure.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param hClass The class handle. NIL_RTLOCKVALCLASS is ok.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncDECL_FORCE_INLINE(RTLOCKVALCLASS) rtLockValidatorClassValidateAndRetain(RTLOCKVALCLASS hClass)
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync{
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync if (hClass == NIL_RTLOCKVALCLASS)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return hClass;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertPtrReturn(hClass, NIL_RTLOCKVALCLASS);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertReturn(hClass->u32Magic == RTLOCKVALCLASS_MAGIC, NIL_RTLOCKVALCLASS);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rtLockValidatorClassRetain(hClass);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return hClass;
af8d59d05d72f134aeea62712f1286b369807d52vboxsync}
af8d59d05d72f134aeea62712f1286b369807d52vboxsync
af8d59d05d72f134aeea62712f1286b369807d52vboxsync
af8d59d05d72f134aeea62712f1286b369807d52vboxsync/**
af8d59d05d72f134aeea62712f1286b369807d52vboxsync * Internal class releaser.
af8d59d05d72f134aeea62712f1286b369807d52vboxsync * @returns The new reference count.
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync * @param pClass The class.
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync */
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsyncDECLINLINE(uint32_t) rtLockValidatorClassRelease(RTLOCKVALCLASSINT *pClass)
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync{
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync uint32_t cRefs = ASMAtomicDecU32(&pClass->cRefs);
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync if (cRefs + 1 == RTLOCKVALCLASS_MAX_REFS)
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync ASMAtomicWriteU32(&pClass->cRefs, RTLOCKVALCLASS_MAX_REFS);
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync else if (!cRefs)
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync rtLockValidatorClassDestroy(pClass);
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync return cRefs;
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync}
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync/**
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync * Destroys a class once there are not more references to it.
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync *
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync * @param Class The class.
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic void rtLockValidatorClassDestroy(RTLOCKVALCLASSINT *pClass)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertReturnVoid(!pClass->fInTree);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteU32(&pClass->u32Magic, RTLOCKVALCLASS_MAGIC_DEAD);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTLOCKVALCLASSREFCHUNK pChunk = &pClass->PriorLocks;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync while (pChunk)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pChunk->aRefs); i++)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTLOCKVALCLASSINT *pClass2 = pChunk->aRefs[i].hClass;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (pClass2 != NIL_RTLOCKVALCLASS)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pChunk->aRefs[i].hClass = NIL_RTLOCKVALCLASS;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rtLockValidatorClassRelease(pClass2);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync PRTLOCKVALCLASSREFCHUNK pNext = pChunk->pNext;
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync pChunk->pNext = NULL;
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync if (pChunk != &pClass->PriorLocks)
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync RTMemFree(pChunk);
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync pChunk = pNext;
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync }
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync RTMemFree(pClass);
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync}
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync
061bebe04c5bfa05ed733d2a1204389c2a0c96a8vboxsync
061bebe04c5bfa05ed733d2a1204389c2a0c96a8vboxsyncRTDECL(RTLOCKVALCLASS) RTLockValidatorClassFindForSrcPos(PRTLOCKVALSRCPOS pSrcPos)
061bebe04c5bfa05ed733d2a1204389c2a0c96a8vboxsync{
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync if (g_hLockValClassTreeRWLock == NIL_RTSEMRW)
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync rtLockValidatorLazyInit();
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync int rcLock = RTSemRWRequestRead(g_hLockValClassTreeRWLock, RT_INDEFINITE_WAIT);
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync uint32_t uSrcPosHash = rtLockValidatorSrcPosHash(pSrcPos);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync RTLOCKVALCLASSINT *pClass = (RTLOCKVALCLASSINT *)RTAvllU32Get(&g_LockValClassTree, uSrcPosHash);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync while (pClass)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync {
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync if (rtLockValidatorSrcPosCompare(&pClass->CreatePos, pSrcPos) == 0)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync break;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pClass = (RTLOCKVALCLASSINT *)pClass->Core.pList;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync }
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync if (RT_SUCCESS(rcLock))
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync RTSemRWReleaseRead(g_hLockValClassTreeRWLock);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync return pClass;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync}
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsyncRTDECL(RTLOCKVALCLASS) RTLockValidatorClassForSrcPos(RT_SRC_POS_DECL, const char *pszNameFmt, ...)
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync{
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_POS_NO_ID();
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync RTLOCKVALCLASS hClass = RTLockValidatorClassFindForSrcPos(&SrcPos);
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync if (hClass == NIL_RTLOCKVALCLASS)
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync {
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync /*
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync * Create a new class and insert it into the tree.
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync */
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync va_list va;
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync va_start(va, pszNameFmt);
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync int rc = RTLockValidatorClassCreateExV(&hClass, &SrcPos,
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync true /*fAutodidact*/, true /*fRecursionOk*/, false /*fStrictReleaseOrder*/,
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync 1 /*cMsMinDeadlock*/, 1 /*cMsMinOrder*/,
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync pszNameFmt, va);
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync va_end(va);
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync if (RT_SUCCESS(rc))
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync {
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync if (g_hLockValClassTreeRWLock == NIL_RTSEMRW)
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync rtLockValidatorLazyInit();
509a2f53cb92e3bf060f4615936354188ce92836vboxsync int rcLock = RTSemRWRequestWrite(g_hLockValClassTreeRWLock, RT_INDEFINITE_WAIT);
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync Assert(!hClass->fInTree);
509a2f53cb92e3bf060f4615936354188ce92836vboxsync hClass->fInTree = RTAvllU32Insert(&g_LockValClassTree, &hClass->Core);
509a2f53cb92e3bf060f4615936354188ce92836vboxsync Assert(hClass->fInTree);
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync if (RT_SUCCESS(rcLock))
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync RTSemRWReleaseWrite(g_hLockValClassTreeRWLock);
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync return hClass;
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync }
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync }
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync return hClass;
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync}
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsyncRTDECL(uint32_t) RTLockValidatorClassRetain(RTLOCKVALCLASS hClass)
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync{
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync RTLOCKVALCLASSINT *pClass = hClass;
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync AssertPtrReturn(pClass, UINT32_MAX);
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync AssertReturn(pClass->u32Magic == RTLOCKVALCLASS_MAGIC, UINT32_MAX);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return rtLockValidatorClassRetain(pClass);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncRTDECL(uint32_t) RTLockValidatorClassRelease(RTLOCKVALCLASS hClass)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTLOCKVALCLASSINT *pClass = hClass;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (pClass == NIL_RTLOCKVALCLASS)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return 0;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertPtrReturn(pClass, UINT32_MAX);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertReturn(pClass->u32Magic == RTLOCKVALCLASS_MAGIC, UINT32_MAX);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return rtLockValidatorClassRelease(pClass);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/**
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Worker for rtLockValidatorClassIsPriorClass that does a linear search thru
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * all the chunks for @a pPriorClass.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @returns true / false.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pClass The class to search.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pPriorClass The class to search for.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic bool rtLockValidatorClassIsPriorClassByLinearSearch(RTLOCKVALCLASSINT *pClass, RTLOCKVALCLASSINT *pPriorClass)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync for (PRTLOCKVALCLASSREFCHUNK pChunk = &pClass->PriorLocks; pChunk; pChunk = pChunk->pNext)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pChunk->aRefs); i++)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (pChunk->aRefs[i].hClass == pPriorClass)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync uint32_t cLookups = ASMAtomicIncU32(&pChunk->aRefs[i].cLookups);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (RT_UNLIKELY(cLookups >= RTLOCKVALCLASSREF_MAX_LOOKUPS_FIX))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteU32(&pChunk->aRefs[i].cLookups, RTLOCKVALCLASSREF_MAX_LOOKUPS);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync cLookups = RTLOCKVALCLASSREF_MAX_LOOKUPS;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /* update the hash table entry. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTLOCKVALCLASSREF *ppHashEntry = &pClass->apPriorLocksHash[RTLOCKVALCLASS_HASH(pPriorClass)];
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if ( !(*ppHashEntry)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync || (*ppHashEntry)->cLookups + 128 < cLookups)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWritePtr(ppHashEntry, &pChunk->aRefs[i]);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#ifdef RTLOCKVAL_WITH_CLASS_HASH_STATS
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicIncU32(&pClass->cHashMisses);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#endif
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return true;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync return false;
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync}
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync/**
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync * Checks if @a pPriorClass is a known prior class.
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync *
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync * @returns true / false.
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync * @param pClass The class to search.
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync * @param pPriorClass The class to search for.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncDECL_FORCE_INLINE(bool) rtLockValidatorClassIsPriorClass(RTLOCKVALCLASSINT *pClass, RTLOCKVALCLASSINT *pPriorClass)
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync{
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync /*
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync * Hash lookup here.
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync */
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync PRTLOCKVALCLASSREF pRef = pClass->apPriorLocksHash[RTLOCKVALCLASS_HASH(pPriorClass)];
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync if ( pRef
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync && pRef->hClass == pPriorClass)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync uint32_t cLookups = ASMAtomicIncU32(&pRef->cLookups);
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync if (RT_UNLIKELY(cLookups >= RTLOCKVALCLASSREF_MAX_LOOKUPS_FIX))
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync ASMAtomicWriteU32(&pRef->cLookups, RTLOCKVALCLASSREF_MAX_LOOKUPS);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#ifdef RTLOCKVAL_WITH_CLASS_HASH_STATS
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync ASMAtomicIncU32(&pClass->cHashHits);
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync#endif
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync return true;
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync }
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync return rtLockValidatorClassIsPriorClassByLinearSearch(pClass, pPriorClass);
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync}
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/**
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Adds a class to the prior list.
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @returns VINF_SUCCESS, VERR_NO_MEMORY or VERR_SEM_LV_WRONG_ORDER.
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync * @param pClass The class to work on.
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync * @param pPriorClass The class to add.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param fAutodidacticism Whether we're teaching ourselves (true) or
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync * somebody is teaching us via the API (false).
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pSrcPos Where this rule was added (optional).
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync */
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsyncstatic int rtLockValidatorClassAddPriorClass(RTLOCKVALCLASSINT *pClass, RTLOCKVALCLASSINT *pPriorClass,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync bool fAutodidacticism, PCRTLOCKVALSRCPOS pSrcPos)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync NOREF(pSrcPos);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (!RTCritSectIsInitialized(&g_LockValClassTeachCS))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rtLockValidatorLazyInit();
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync int rcLock = RTCritSectEnter(&g_LockValClassTeachCS);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /*
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Check that there are no conflict (no assert since we might race each other).
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync int rc = VERR_SEM_LV_INTERNAL_ERROR;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (!rtLockValidatorClassIsPriorClass(pPriorClass, pClass))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (!rtLockValidatorClassIsPriorClass(pClass, pPriorClass))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /*
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Scan the table for a free entry, allocating a new chunk if necessary.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync for (PRTLOCKVALCLASSREFCHUNK pChunk = &pClass->PriorLocks; ; pChunk = pChunk->pNext)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync bool fDone = false;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pChunk->aRefs); i++)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicCmpXchgHandle(&pChunk->aRefs[i].hClass, pPriorClass, NIL_RTLOCKVALCLASS, fDone);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (fDone)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pChunk->aRefs[i].fAutodidacticism = fAutodidacticism;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rtLockValidatorClassRetain(pPriorClass);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rc = VINF_SUCCESS;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync break;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (fDone)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync break;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /* If no more chunks, allocate a new one and insert the class before linking it. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (!pChunk->pNext)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTLOCKVALCLASSREFCHUNK pNew = (PRTLOCKVALCLASSREFCHUNK)RTMemAlloc(sizeof(*pNew));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (!pNew)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rc = VERR_NO_MEMORY;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync break;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pNew->pNext = NULL;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pNew->aRefs); i++)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pNew->aRefs[i].hClass = NIL_RTLOCKVALCLASS;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pNew->aRefs[i].cLookups = 0;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pNew->aRefs[i].fAutodidacticism = false;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pNew->aRefs[i].afReserved[0] = false;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pNew->aRefs[i].afReserved[1] = false;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pNew->aRefs[i].afReserved[2] = false;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pNew->aRefs[0].hClass = pPriorClass;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pNew->aRefs[0].fAutodidacticism = fAutodidacticism;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWritePtr(&pChunk->pNext, pNew);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync rtLockValidatorClassRetain(pPriorClass);
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync rc = VINF_SUCCESS;
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync break;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync }
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync } /* chunk loop */
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync }
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync else
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync rc = VINF_SUCCESS;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync }
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync else
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rc = !g_fLockValSoftWrongOrder ? VERR_SEM_LV_WRONG_ORDER : VINF_SUCCESS;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (RT_SUCCESS(rcLock))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTCritSectLeave(&g_LockValClassTeachCS);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return rc;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncRTDECL(int) RTLockValidatorClassAddPriorClass(RTLOCKVALCLASS hClass, RTLOCKVALCLASS hPriorClass)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTLOCKVALCLASSINT *pClass = hClass;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertPtrReturn(pClass, VERR_INVALID_HANDLE);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertReturn(pClass->u32Magic == RTLOCKVALCLASS_MAGIC, VERR_INVALID_HANDLE);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTLOCKVALCLASSINT *pPriorClass = hPriorClass;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertPtrReturn(pPriorClass, VERR_INVALID_HANDLE);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertReturn(pPriorClass->u32Magic == RTLOCKVALCLASS_MAGIC, VERR_INVALID_HANDLE);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return rtLockValidatorClassAddPriorClass(pClass, pPriorClass, false /*fAutodidacticism*/, NULL);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncRTDECL(int) RTLockValidatorClassEnforceStrictReleaseOrder(RTLOCKVALCLASS hClass, bool fEnabled)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTLOCKVALCLASSINT *pClass = hClass;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertPtrReturn(pClass, VERR_INVALID_HANDLE);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertReturn(pClass->u32Magic == RTLOCKVALCLASS_MAGIC, VERR_INVALID_HANDLE);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteBool(&pClass->fStrictReleaseOrder, fEnabled);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return VINF_SUCCESS;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/**
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Unlinks all siblings.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * This is used during record deletion and assumes no races.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pCore One of the siblings.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic void rtLockValidatorUnlinkAllSiblings(PRTLOCKVALRECCORE pCore)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /* ASSUMES sibling destruction doesn't involve any races and that all
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync related records are to be disposed off now. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTLOCKVALRECUNION pSibling = (PRTLOCKVALRECUNION)pCore;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync while (pSibling)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTLOCKVALRECUNION volatile *ppCoreNext;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync switch (pSibling->Core.u32Magic)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync case RTLOCKVALRECEXCL_MAGIC:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync case RTLOCKVALRECEXCL_MAGIC_DEAD:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ppCoreNext = &pSibling->Excl.pSibling;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync break;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync case RTLOCKVALRECSHRD_MAGIC:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync case RTLOCKVALRECSHRD_MAGIC_DEAD:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ppCoreNext = &pSibling->Shared.pSibling;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync break;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync default:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertFailed();
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ppCoreNext = NULL;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync break;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (RT_UNLIKELY(ppCoreNext))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync break;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pSibling = ASMAtomicXchgPtrT(ppCoreNext, NULL, PRTLOCKVALRECUNION);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncRTDECL(int) RTLockValidatorRecMakeSiblings(PRTLOCKVALRECCORE pRec1, PRTLOCKVALRECCORE pRec2)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /*
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Validate input.
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTLOCKVALRECUNION p1 = (PRTLOCKVALRECUNION)pRec1;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTLOCKVALRECUNION p2 = (PRTLOCKVALRECUNION)pRec2;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertPtrReturn(p1, VERR_SEM_LV_INVALID_PARAMETER);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertReturn( p1->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync || p1->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync , VERR_SEM_LV_INVALID_PARAMETER);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertPtrReturn(p2, VERR_SEM_LV_INVALID_PARAMETER);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertReturn( p2->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync || p2->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync , VERR_SEM_LV_INVALID_PARAMETER);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /*
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Link them (circular list).
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if ( p1->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync && p2->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync p1->Excl.pSibling = p2;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync p2->Shared.pSibling = p1;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync else if ( p1->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync && p2->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync p1->Shared.pSibling = p2;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync p2->Excl.pSibling = p1;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync else
885ac2b8c00cb7f4878e9108f40e1a43ff756e35vboxsync AssertFailedReturn(VERR_SEM_LV_INVALID_PARAMETER); /* unsupported mix */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return VINF_SUCCESS;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/**
885ac2b8c00cb7f4878e9108f40e1a43ff756e35vboxsync * Gets the lock name for the given record.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @returns Read-only lock name.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pRec The lock record.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncDECL_FORCE_INLINE(const char *) rtLockValidatorRecName(PRTLOCKVALRECUNION pRec)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
885ac2b8c00cb7f4878e9108f40e1a43ff756e35vboxsync switch (pRec->Core.u32Magic)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync case RTLOCKVALRECEXCL_MAGIC:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return pRec->Excl.szName;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync case RTLOCKVALRECSHRD_MAGIC:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return pRec->Shared.szName;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync case RTLOCKVALRECSHRDOWN_MAGIC:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return pRec->ShrdOwner.pSharedRec ? pRec->ShrdOwner.pSharedRec->szName : "orphaned";
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync case RTLOCKVALRECNEST_MAGIC:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pRec = rtLockValidatorReadRecUnionPtr(&pRec->Nest.pRec);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (VALID_PTR(pRec))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync switch (pRec->Core.u32Magic)
885ac2b8c00cb7f4878e9108f40e1a43ff756e35vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync case RTLOCKVALRECEXCL_MAGIC:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return pRec->Excl.szName;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync case RTLOCKVALRECSHRD_MAGIC:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return pRec->Shared.szName;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync case RTLOCKVALRECSHRDOWN_MAGIC:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return pRec->ShrdOwner.pSharedRec ? pRec->ShrdOwner.pSharedRec->szName : "orphaned";
885ac2b8c00cb7f4878e9108f40e1a43ff756e35vboxsync default:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return "unknown-nested";
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return "orphaned-nested";
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync default:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return "unknown";
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/**
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Gets the class for this locking record.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @returns Pointer to the class or NIL_RTLOCKVALCLASS.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pRec The lock validator record.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncDECLINLINE(RTLOCKVALCLASSINT *) rtLockValidatorRecGetClass(PRTLOCKVALRECUNION pRec)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync switch (pRec->Core.u32Magic)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync case RTLOCKVALRECEXCL_MAGIC:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return pRec->Excl.hClass;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync case RTLOCKVALRECSHRD_MAGIC:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return pRec->Shared.hClass;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync case RTLOCKVALRECSHRDOWN_MAGIC:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTLOCKVALRECSHRD pSharedRec = pRec->ShrdOwner.pSharedRec;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (RT_LIKELY( VALID_PTR(pSharedRec)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync && pSharedRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return pSharedRec->hClass;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return NIL_RTLOCKVALCLASS;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync case RTLOCKVALRECNEST_MAGIC:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTLOCKVALRECUNION pRealRec = pRec->Nest.pRec;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (VALID_PTR(pRealRec))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync switch (pRealRec->Core.u32Magic)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync case RTLOCKVALRECEXCL_MAGIC:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return pRealRec->Excl.hClass;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync case RTLOCKVALRECSHRDOWN_MAGIC:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync PRTLOCKVALRECSHRD pSharedRec = pRealRec->ShrdOwner.pSharedRec;
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync if (RT_LIKELY( VALID_PTR(pSharedRec)
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync && pSharedRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC))
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync return pSharedRec->hClass;
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync break;
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync }
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync default:
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync AssertMsgFailed(("%p %p %#x\n", pRec, pRealRec, pRealRec->Core.u32Magic));
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync break;
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync }
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return NIL_RTLOCKVALCLASS;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync default:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertMsgFailed(("%#x\n", pRec->Core.u32Magic));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return NIL_RTLOCKVALCLASS;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync}
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync/**
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync * Gets the class for this locking record and the pointer to the one below it in
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync * the stack.
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync *
af8d59d05d72f134aeea62712f1286b369807d52vboxsync * @returns Pointer to the class or NIL_RTLOCKVALCLASS.
af8d59d05d72f134aeea62712f1286b369807d52vboxsync * @param pRec The lock validator record.
af8d59d05d72f134aeea62712f1286b369807d52vboxsync * @param puSubClass Where to return the sub-class.
af8d59d05d72f134aeea62712f1286b369807d52vboxsync * @param ppDown Where to return the pointer to the record below.
af8d59d05d72f134aeea62712f1286b369807d52vboxsync */
af8d59d05d72f134aeea62712f1286b369807d52vboxsyncDECL_FORCE_INLINE(RTLOCKVALCLASSINT *)
af8d59d05d72f134aeea62712f1286b369807d52vboxsyncrtLockValidatorRecGetClassesAndDown(PRTLOCKVALRECUNION pRec, uint32_t *puSubClass, PRTLOCKVALRECUNION *ppDown)
af8d59d05d72f134aeea62712f1286b369807d52vboxsync{
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync switch (pRec->Core.u32Magic)
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync {
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync case RTLOCKVALRECEXCL_MAGIC:
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync *ppDown = pRec->Excl.pDown;
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync *puSubClass = pRec->Excl.uSubClass;
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync return pRec->Excl.hClass;
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync case RTLOCKVALRECSHRD_MAGIC:
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync *ppDown = NULL;
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync *puSubClass = pRec->Shared.uSubClass;
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync return pRec->Shared.hClass;
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync case RTLOCKVALRECSHRDOWN_MAGIC:
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync {
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync *ppDown = pRec->ShrdOwner.pDown;
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync PRTLOCKVALRECSHRD pSharedRec = pRec->ShrdOwner.pSharedRec;
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync if (RT_LIKELY( VALID_PTR(pSharedRec)
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync && pSharedRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *puSubClass = pSharedRec->uSubClass;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return pSharedRec->hClass;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *puSubClass = RTLOCKVAL_SUB_CLASS_NONE;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return NIL_RTLOCKVALCLASS;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync case RTLOCKVALRECNEST_MAGIC:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *ppDown = pRec->Nest.pDown;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTLOCKVALRECUNION pRealRec = pRec->Nest.pRec;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (VALID_PTR(pRealRec))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync switch (pRealRec->Core.u32Magic)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync case RTLOCKVALRECEXCL_MAGIC:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *puSubClass = pRealRec->Excl.uSubClass;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return pRealRec->Excl.hClass;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync case RTLOCKVALRECSHRDOWN_MAGIC:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTLOCKVALRECSHRD pSharedRec = pRealRec->ShrdOwner.pSharedRec;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (RT_LIKELY( VALID_PTR(pSharedRec)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync && pSharedRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *puSubClass = pSharedRec->uSubClass;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return pSharedRec->hClass;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync break;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync default:
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync AssertMsgFailed(("%p %p %#x\n", pRec, pRealRec, pRealRec->Core.u32Magic));
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync break;
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync }
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync }
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync *puSubClass = RTLOCKVAL_SUB_CLASS_NONE;
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync return NIL_RTLOCKVALCLASS;
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync }
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync default:
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync AssertMsgFailed(("%#x\n", pRec->Core.u32Magic));
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync *ppDown = NULL;
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync *puSubClass = RTLOCKVAL_SUB_CLASS_NONE;
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync return NIL_RTLOCKVALCLASS;
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync }
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync}
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync/**
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync * Gets the sub-class for a lock record.
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync *
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync * @returns the sub-class.
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync * @param pRec The lock validator record.
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync */
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsyncDECLINLINE(uint32_t) rtLockValidatorRecGetSubClass(PRTLOCKVALRECUNION pRec)
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync{
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync switch (pRec->Core.u32Magic)
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync {
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync case RTLOCKVALRECEXCL_MAGIC:
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync return pRec->Excl.uSubClass;
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync case RTLOCKVALRECSHRD_MAGIC:
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync return pRec->Shared.uSubClass;
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync case RTLOCKVALRECSHRDOWN_MAGIC:
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync {
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync PRTLOCKVALRECSHRD pSharedRec = pRec->ShrdOwner.pSharedRec;
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync if (RT_LIKELY( VALID_PTR(pSharedRec)
061bebe04c5bfa05ed733d2a1204389c2a0c96a8vboxsync && pSharedRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC))
061bebe04c5bfa05ed733d2a1204389c2a0c96a8vboxsync return pSharedRec->uSubClass;
061bebe04c5bfa05ed733d2a1204389c2a0c96a8vboxsync return RTLOCKVAL_SUB_CLASS_NONE;
061bebe04c5bfa05ed733d2a1204389c2a0c96a8vboxsync }
061bebe04c5bfa05ed733d2a1204389c2a0c96a8vboxsync
061bebe04c5bfa05ed733d2a1204389c2a0c96a8vboxsync case RTLOCKVALRECNEST_MAGIC:
061bebe04c5bfa05ed733d2a1204389c2a0c96a8vboxsync {
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync PRTLOCKVALRECUNION pRealRec = pRec->Nest.pRec;
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync if (VALID_PTR(pRealRec))
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync {
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync switch (pRealRec->Core.u32Magic)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync {
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync case RTLOCKVALRECEXCL_MAGIC:
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync return pRec->Excl.uSubClass;
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync case RTLOCKVALRECSHRDOWN_MAGIC:
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync {
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync PRTLOCKVALRECSHRD pSharedRec = pRealRec->ShrdOwner.pSharedRec;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync if (RT_LIKELY( VALID_PTR(pSharedRec)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync && pSharedRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC))
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync return pSharedRec->uSubClass;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync break;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync }
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync default:
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync AssertMsgFailed(("%p %p %#x\n", pRec, pRealRec, pRealRec->Core.u32Magic));
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync break;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync }
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync }
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync return RTLOCKVAL_SUB_CLASS_NONE;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync }
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync default:
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync AssertMsgFailed(("%#x\n", pRec->Core.u32Magic));
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync return RTLOCKVAL_SUB_CLASS_NONE;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync }
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync}
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync/**
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * Calculates the depth of a lock stack.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync *
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @returns Number of stack frames.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @param pThread The thread.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync */
6e7c344fc7cdb580356704e8201207b394d367bbvboxsyncstatic uint32_t rtLockValidatorStackDepth(PRTTHREADINT pThread)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync{
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync uint32_t cEntries = 0;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync PRTLOCKVALRECUNION pCur = rtLockValidatorReadRecUnionPtr(&pThread->LockValidator.pStackTop);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync while (VALID_PTR(pCur))
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync {
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync switch (pCur->Core.u32Magic)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync {
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync case RTLOCKVALRECEXCL_MAGIC:
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pCur = rtLockValidatorReadRecUnionPtr(&pCur->Excl.pDown);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync break;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync case RTLOCKVALRECSHRDOWN_MAGIC:
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pCur = rtLockValidatorReadRecUnionPtr(&pCur->ShrdOwner.pDown);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync break;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync case RTLOCKVALRECNEST_MAGIC:
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pCur = rtLockValidatorReadRecUnionPtr(&pCur->Nest.pDown);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync break;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync default:
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync AssertMsgFailedReturn(("%#x\n", pCur->Core.u32Magic), cEntries);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync }
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync cEntries++;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync }
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync return cEntries;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync}
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync#ifdef RT_STRICT
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync/**
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * Checks if the stack contains @a pRec.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync *
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @returns true / false.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @param pThreadSelf The current thread.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @param pRec The lock record.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync */
6e7c344fc7cdb580356704e8201207b394d367bbvboxsyncstatic bool rtLockValidatorStackContainsRec(PRTTHREADINT pThreadSelf, PRTLOCKVALRECUNION pRec)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync{
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync PRTLOCKVALRECUNION pCur = pThreadSelf->LockValidator.pStackTop;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync while (pCur)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync {
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync AssertPtrReturn(pCur, false);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync if (pCur == pRec)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync return true;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync switch (pCur->Core.u32Magic)
4a82b347bce2c97db4707d994221b4c20437b520vboxsync {
4a82b347bce2c97db4707d994221b4c20437b520vboxsync case RTLOCKVALRECEXCL_MAGIC:
4a82b347bce2c97db4707d994221b4c20437b520vboxsync Assert(pCur->Excl.cRecursion >= 1);
4a82b347bce2c97db4707d994221b4c20437b520vboxsync pCur = pCur->Excl.pDown;
4a82b347bce2c97db4707d994221b4c20437b520vboxsync break;
4a82b347bce2c97db4707d994221b4c20437b520vboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync case RTLOCKVALRECSHRDOWN_MAGIC:
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync Assert(pCur->ShrdOwner.cRecursion >= 1);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pCur = pCur->ShrdOwner.pDown;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync break;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync case RTLOCKVALRECNEST_MAGIC:
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync Assert(pCur->Nest.cRecursion > 1);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pCur = pCur->Nest.pDown;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync break;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync default:
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync AssertMsgFailedReturn(("%#x\n", pCur->Core.u32Magic), false);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync }
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync }
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync return false;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync}
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync#endif /* RT_STRICT */
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync/**
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * Pushes a lock record onto the stack.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync *
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @param pThreadSelf The current thread.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @param pRec The lock record.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync */
6e7c344fc7cdb580356704e8201207b394d367bbvboxsyncstatic void rtLockValidatorStackPush(PRTTHREADINT pThreadSelf, PRTLOCKVALRECUNION pRec)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync{
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync Assert(pThreadSelf == RTThreadSelf());
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync Assert(!rtLockValidatorStackContainsRec(pThreadSelf, pRec));
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync switch (pRec->Core.u32Magic)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync {
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync case RTLOCKVALRECEXCL_MAGIC:
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync Assert(pRec->Excl.cRecursion == 1);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync Assert(pRec->Excl.pDown == NULL);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync rtLockValidatorWriteRecUnionPtr(&pRec->Excl.pDown, pThreadSelf->LockValidator.pStackTop);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync break;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync case RTLOCKVALRECSHRDOWN_MAGIC:
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync Assert(pRec->ShrdOwner.cRecursion == 1);
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync Assert(pRec->ShrdOwner.pDown == NULL);
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync rtLockValidatorWriteRecUnionPtr(&pRec->ShrdOwner.pDown, pThreadSelf->LockValidator.pStackTop);
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync break;
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync default:
509a2f53cb92e3bf060f4615936354188ce92836vboxsync AssertMsgFailedReturnVoid(("%#x\n", pRec->Core.u32Magic));
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync }
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync rtLockValidatorWriteRecUnionPtr(&pThreadSelf->LockValidator.pStackTop, pRec);
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync}
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync/**
509a2f53cb92e3bf060f4615936354188ce92836vboxsync * Pops a lock record off the stack.
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync *
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync * @param pThreadSelf The current thread.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * @param pRec The lock.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsyncstatic void rtLockValidatorStackPop(PRTTHREADINT pThreadSelf, PRTLOCKVALRECUNION pRec)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync{
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync Assert(pThreadSelf == RTThreadSelf());
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync PRTLOCKVALRECUNION pDown;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync switch (pRec->Core.u32Magic)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync {
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync case RTLOCKVALRECEXCL_MAGIC:
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync Assert(pRec->Excl.cRecursion == 0);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pDown = pRec->Excl.pDown;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValidatorWriteRecUnionPtr(&pRec->Excl.pDown, NULL); /* lazy bird */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync break;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync case RTLOCKVALRECSHRDOWN_MAGIC:
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync Assert(pRec->ShrdOwner.cRecursion == 0);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pDown = pRec->ShrdOwner.pDown;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValidatorWriteRecUnionPtr(&pRec->ShrdOwner.pDown, NULL);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync break;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync default:
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync AssertMsgFailedReturnVoid(("%#x\n", pRec->Core.u32Magic));
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync }
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync if (pThreadSelf->LockValidator.pStackTop == pRec)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValidatorWriteRecUnionPtr(&pThreadSelf->LockValidator.pStackTop, pDown);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync else
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync {
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync /* Find the pointer to our record and unlink ourselves. */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync PRTLOCKVALRECUNION pCur = pThreadSelf->LockValidator.pStackTop;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync while (pCur)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync {
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync PRTLOCKVALRECUNION volatile *ppDown;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync switch (pCur->Core.u32Magic)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync {
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync case RTLOCKVALRECEXCL_MAGIC:
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync Assert(pCur->Excl.cRecursion >= 1);
af8d59d05d72f134aeea62712f1286b369807d52vboxsync ppDown = &pCur->Excl.pDown;
af8d59d05d72f134aeea62712f1286b369807d52vboxsync break;
af8d59d05d72f134aeea62712f1286b369807d52vboxsync
af8d59d05d72f134aeea62712f1286b369807d52vboxsync case RTLOCKVALRECSHRDOWN_MAGIC:
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync Assert(pCur->ShrdOwner.cRecursion >= 1);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync ppDown = &pCur->ShrdOwner.pDown;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync break;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync case RTLOCKVALRECNEST_MAGIC:
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync Assert(pCur->Nest.cRecursion >= 1);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync ppDown = &pCur->Nest.pDown;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync break;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync default:
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync AssertMsgFailedReturnVoid(("%#x\n", pCur->Core.u32Magic));
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync }
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pCur = *ppDown;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync if (pCur == pRec)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync {
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValidatorWriteRecUnionPtr(ppDown, pDown);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync return;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync }
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync }
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync AssertMsgFailed(("%p %p\n", pRec, pThreadSelf));
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync }
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync}
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync/**
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Creates and pushes lock recursion record onto the stack.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync *
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * @param pThreadSelf The current thread.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * @param pRec The lock record.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * @param pSrcPos Where the recursion occurred.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsyncstatic void rtLockValidatorStackPushRecursion(PRTTHREADINT pThreadSelf, PRTLOCKVALRECUNION pRec, PCRTLOCKVALSRCPOS pSrcPos)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync{
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync Assert(pThreadSelf == RTThreadSelf());
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync Assert(rtLockValidatorStackContainsRec(pThreadSelf, pRec));
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync#ifdef RTLOCKVAL_WITH_RECURSION_RECORDS
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync /*
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Allocate a new recursion record
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync PRTLOCKVALRECNEST pRecursionRec = pThreadSelf->LockValidator.pFreeNestRecs;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync if (pRecursionRec)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pThreadSelf->LockValidator.pFreeNestRecs = pRecursionRec->pNextFree;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync else
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync {
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pRecursionRec = (PRTLOCKVALRECNEST)RTMemAlloc(sizeof(*pRecursionRec));
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync if (!pRecursionRec)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync return;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync }
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync /*
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Initialize it.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync switch (pRec->Core.u32Magic)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync {
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync case RTLOCKVALRECEXCL_MAGIC:
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pRecursionRec->cRecursion = pRec->Excl.cRecursion;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync break;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync case RTLOCKVALRECSHRDOWN_MAGIC:
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pRecursionRec->cRecursion = pRec->ShrdOwner.cRecursion;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync break;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync default:
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync AssertMsgFailed(("%#x\n", pRec->Core.u32Magic));
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValidatorSerializeDestructEnter();
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValidatorSerializeDestructLeave();
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync RTMemFree(pRecursionRec);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync return;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync }
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync Assert(pRecursionRec->cRecursion > 1);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pRecursionRec->pRec = pRec;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pRecursionRec->pDown = NULL;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pRecursionRec->pNextFree = NULL;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValidatorSrcPosCopy(&pRecursionRec->SrcPos, pSrcPos);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pRecursionRec->Core.u32Magic = RTLOCKVALRECNEST_MAGIC;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync /*
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Link it.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pRecursionRec->pDown = pThreadSelf->LockValidator.pStackTop;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValidatorWriteRecUnionPtr(&pThreadSelf->LockValidator.pStackTop, (PRTLOCKVALRECUNION)pRecursionRec);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync#endif /* RTLOCKVAL_WITH_RECURSION_RECORDS */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync}
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync/**
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Pops a lock recursion record off the stack.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync *
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * @param pThreadSelf The current thread.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * @param pRec The lock record.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsyncstatic void rtLockValidatorStackPopRecursion(PRTTHREADINT pThreadSelf, PRTLOCKVALRECUNION pRec)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync{
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync Assert(pThreadSelf == RTThreadSelf());
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync Assert(rtLockValidatorStackContainsRec(pThreadSelf, pRec));
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync uint32_t cRecursion;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync switch (pRec->Core.u32Magic)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync {
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync case RTLOCKVALRECEXCL_MAGIC: cRecursion = pRec->Excl.cRecursion; break;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync case RTLOCKVALRECSHRDOWN_MAGIC: cRecursion = pRec->ShrdOwner.cRecursion; break;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync default: AssertMsgFailedReturnVoid(("%#x\n", pRec->Core.u32Magic));
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync }
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync Assert(cRecursion >= 1);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync#ifdef RTLOCKVAL_WITH_RECURSION_RECORDS
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync /*
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Pop the recursion record.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync PRTLOCKVALRECUNION pNest = pThreadSelf->LockValidator.pStackTop;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync if ( pNest != NULL
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync && pNest->Core.u32Magic == RTLOCKVALRECNEST_MAGIC
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync && pNest->Nest.pRec == pRec
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync )
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync {
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync Assert(pNest->Nest.cRecursion == cRecursion + 1);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValidatorWriteRecUnionPtr(&pThreadSelf->LockValidator.pStackTop, pNest->Nest.pDown);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync }
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync else
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync {
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync /* Find the record above ours. */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync PRTLOCKVALRECUNION volatile *ppDown = NULL;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync for (;;)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync {
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync AssertMsgReturnVoid(pNest, ("%p %p\n", pRec, pThreadSelf));
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync switch (pNest->Core.u32Magic)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync {
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync case RTLOCKVALRECEXCL_MAGIC:
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync ppDown = &pNest->Excl.pDown;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pNest = *ppDown;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync continue;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync case RTLOCKVALRECSHRDOWN_MAGIC:
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync ppDown = &pNest->ShrdOwner.pDown;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pNest = *ppDown;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync continue;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync case RTLOCKVALRECNEST_MAGIC:
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync if (pNest->Nest.pRec == pRec)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync break;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync ppDown = &pNest->Nest.pDown;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pNest = *ppDown;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync continue;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync default:
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync AssertMsgFailedReturnVoid(("%#x\n", pNest->Core.u32Magic));
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync }
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync break; /* ugly */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync }
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync Assert(pNest->Nest.cRecursion == cRecursion + 1);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValidatorWriteRecUnionPtr(ppDown, pNest->Nest.pDown);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync }
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync /*
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Invalidate and free the record.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync ASMAtomicWriteU32(&pNest->Core.u32Magic, RTLOCKVALRECNEST_MAGIC);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValidatorWriteRecUnionPtr(&pNest->Nest.pDown, NULL);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValidatorWriteRecUnionPtr(&pNest->Nest.pRec, NULL);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pNest->Nest.cRecursion = 0;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pNest->Nest.pNextFree = pThreadSelf->LockValidator.pFreeNestRecs;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pThreadSelf->LockValidator.pFreeNestRecs = &pNest->Nest;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync#endif /* RTLOCKVAL_WITH_RECURSION_RECORDS */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync}
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync/**
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Helper for rtLockValidatorStackCheckLockingOrder that does the bitching and
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * returns VERR_SEM_LV_WRONG_ORDER.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsyncstatic int rtLockValidatorStackWrongOrder(const char *pszWhat, PCRTLOCKVALSRCPOS pSrcPos, PRTTHREADINT pThreadSelf,
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync PRTLOCKVALRECUNION pRec1, PRTLOCKVALRECUNION pRec2,
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync RTLOCKVALCLASSINT *pClass1, RTLOCKVALCLASSINT *pClass2)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync{
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValComplainFirst(pszWhat, pSrcPos, pThreadSelf, pRec1, false);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValComplainAboutLock("Other lock: ", pRec2, "\n");
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValComplainAboutClass("My class: ", pClass1, rtLockValidatorRecGetSubClass(pRec1), true /*fVerbose*/);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValComplainAboutClass("Other class: ", pClass2, rtLockValidatorRecGetSubClass(pRec2), true /*fVerbose*/);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValComplainAboutLockStack(pThreadSelf, 0, 0, pRec2);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValComplainPanic();
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync return !g_fLockValSoftWrongOrder ? VERR_SEM_LV_WRONG_ORDER : VINF_SUCCESS;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync}
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync/**
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Checks if the sub-class order is ok or not.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync *
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Used to deal with two locks from the same class.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync *
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * @returns true if ok, false if not.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * @param uSubClass1 The sub-class of the lock that is being
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * considered.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * @param uSubClass2 The sub-class of the lock that is already being
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * held.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsyncDECL_FORCE_INLINE(bool) rtLockValidatorIsSubClassOrderOk(uint32_t uSubClass1, uint32_t uSubClass2)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync{
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync if (uSubClass1 > uSubClass2)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync {
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync /* NONE kills ANY. */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync if (uSubClass2 == RTLOCKVAL_SUB_CLASS_NONE)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync return false;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync return true;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync }
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync /* ANY counters all USER values. (uSubClass1 == NONE only if they are equal) */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync AssertCompile(RTLOCKVAL_SUB_CLASS_ANY > RTLOCKVAL_SUB_CLASS_NONE);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync if (uSubClass1 == RTLOCKVAL_SUB_CLASS_ANY)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync return true;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync return false;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync}
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync/**
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Checks if the class and sub-class lock order is ok.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync *
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * @returns true if ok, false if not.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * @param pClass1 The class of the lock that is being considered.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * @param uSubClass1 The sub-class that goes with @a pClass1.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * @param pClass2 The class of the lock that is already being
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * held.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * @param uSubClass2 The sub-class that goes with @a pClass2.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsyncDECL_FORCE_INLINE(bool) rtLockValidatorIsClassOrderOk(RTLOCKVALCLASSINT *pClass1, uint32_t uSubClass1,
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync RTLOCKVALCLASSINT *pClass2, uint32_t uSubClass2)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync{
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync if (pClass1 == pClass2)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync return rtLockValidatorIsSubClassOrderOk(uSubClass1, uSubClass2);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync return rtLockValidatorClassIsPriorClass(pClass1, pClass2);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
/**
* Checks the locking order, part two.
*
* @returns VINF_SUCCESS, VERR_SEM_LV_WRONG_ORDER or VERR_SEM_LV_INTERNAL_ERROR.
* @param pClass The lock class.
* @param uSubClass The lock sub-class.
* @param pThreadSelf The current thread.
* @param pRec The lock record.
* @param pSrcPos The source position of the locking operation.
*/
static int rtLockValidatorStackCheckLockingOrder2(RTLOCKVALCLASSINT * const pClass, uint32_t const uSubClass,
PRTTHREADINT pThreadSelf, PRTLOCKVALRECUNION const pRec,
PCRTLOCKVALSRCPOS const pSrcPos,
RTLOCKVALCLASSINT * const pFirstBadClass,
PRTLOCKVALRECUNION const pFirstBadRec,
PRTLOCKVALRECUNION const pFirstBadDown)
{
/*
* Something went wrong, pCur is pointing to where.
*/
if ( pClass == pFirstBadClass
|| rtLockValidatorClassIsPriorClass(pFirstBadClass, pClass))
return rtLockValidatorStackWrongOrder("Wrong locking order!", pSrcPos, pThreadSelf,
pRec, pFirstBadRec, pClass, pFirstBadClass);
if (!pClass->fAutodidact)
return rtLockValidatorStackWrongOrder("Wrong locking order! (unknown)", pSrcPos, pThreadSelf,
pRec, pFirstBadRec, pClass, pFirstBadClass);
/*
* This class is an autodidact, so we have to check out the rest of the stack
* for direct violations.
*/
uint32_t cNewRules = 1;
PRTLOCKVALRECUNION pCur = pFirstBadDown;
while (pCur)
{
AssertPtrReturn(pCur, VERR_SEM_LV_INTERNAL_ERROR);
if (pCur->Core.u32Magic == RTLOCKVALRECNEST_MAGIC)
pCur = pCur->Nest.pDown;
else
{
PRTLOCKVALRECUNION pDown;
uint32_t uPriorSubClass;
RTLOCKVALCLASSINT *pPriorClass = rtLockValidatorRecGetClassesAndDown(pCur, &uPriorSubClass, &pDown);
if (pPriorClass != NIL_RTLOCKVALCLASS)
{
AssertPtrReturn(pPriorClass, VERR_SEM_LV_INTERNAL_ERROR);
AssertReturn(pPriorClass->u32Magic == RTLOCKVALCLASS_MAGIC, VERR_SEM_LV_INTERNAL_ERROR);
if (!rtLockValidatorIsClassOrderOk(pClass, uSubClass, pPriorClass, uPriorSubClass))
{
if ( pClass == pPriorClass
|| rtLockValidatorClassIsPriorClass(pPriorClass, pClass))
return rtLockValidatorStackWrongOrder("Wrong locking order! (more than one)", pSrcPos, pThreadSelf,
pRec, pCur, pClass, pPriorClass);
cNewRules++;
}
}
pCur = pDown;
}
}
if (cNewRules == 1)
{
/*
* Special case the simple operation, hoping that it will be a
* frequent case.
*/
int rc = rtLockValidatorClassAddPriorClass(pClass, pFirstBadClass, true /*fAutodidacticism*/, pSrcPos);
if (rc == VERR_SEM_LV_WRONG_ORDER)
return rtLockValidatorStackWrongOrder("Wrong locking order! (race)", pSrcPos, pThreadSelf,
pRec, pFirstBadRec, pClass, pFirstBadClass);
Assert(RT_SUCCESS(rc) || rc == VERR_NO_MEMORY);
}
else
{
/*
* We may be adding more than one rule, so we have to take the lock
* before starting to add the rules. This means we have to check
* the state after taking it since we might be racing someone adding
* a conflicting rule.
*/
if (!RTCritSectIsInitialized(&g_LockValClassTeachCS))
rtLockValidatorLazyInit();
int rcLock = RTCritSectEnter(&g_LockValClassTeachCS);
/* Check */
pCur = pFirstBadRec;
while (pCur)
{
if (pCur->Core.u32Magic == RTLOCKVALRECNEST_MAGIC)
pCur = pCur->Nest.pDown;
else
{
uint32_t uPriorSubClass;
PRTLOCKVALRECUNION pDown;
RTLOCKVALCLASSINT *pPriorClass = rtLockValidatorRecGetClassesAndDown(pCur, &uPriorSubClass, &pDown);
if (pPriorClass != NIL_RTLOCKVALCLASS)
{
if (!rtLockValidatorIsClassOrderOk(pClass, uSubClass, pPriorClass, uPriorSubClass))
{
if ( pClass == pPriorClass
|| rtLockValidatorClassIsPriorClass(pPriorClass, pClass))
{
if (RT_SUCCESS(rcLock))
RTCritSectLeave(&g_LockValClassTeachCS);
return rtLockValidatorStackWrongOrder("Wrong locking order! (2nd)", pSrcPos, pThreadSelf,
pRec, pCur, pClass, pPriorClass);
}
}
}
pCur = pDown;
}
}
/* Iterate the stack yet again, adding new rules this time. */
pCur = pFirstBadRec;
while (pCur)
{
if (pCur->Core.u32Magic == RTLOCKVALRECNEST_MAGIC)
pCur = pCur->Nest.pDown;
else
{
uint32_t uPriorSubClass;
PRTLOCKVALRECUNION pDown;
RTLOCKVALCLASSINT *pPriorClass = rtLockValidatorRecGetClassesAndDown(pCur, &uPriorSubClass, &pDown);
if (pPriorClass != NIL_RTLOCKVALCLASS)
{
if (!rtLockValidatorIsClassOrderOk(pClass, uSubClass, pPriorClass, uPriorSubClass))
{
Assert( pClass != pPriorClass
&& !rtLockValidatorClassIsPriorClass(pPriorClass, pClass));
int rc = rtLockValidatorClassAddPriorClass(pClass, pPriorClass, true /*fAutodidacticism*/, pSrcPos);
if (RT_FAILURE(rc))
{
Assert(rc == VERR_NO_MEMORY);
break;
}
Assert(rtLockValidatorClassIsPriorClass(pClass, pPriorClass));
}
}
pCur = pDown;
}
}
if (RT_SUCCESS(rcLock))
RTCritSectLeave(&g_LockValClassTeachCS);
}
return VINF_SUCCESS;
}
/**
* Checks the locking order.
*
* @returns VINF_SUCCESS, VERR_SEM_LV_WRONG_ORDER or VERR_SEM_LV_INTERNAL_ERROR.
* @param pClass The lock class.
* @param uSubClass The lock sub-class.
* @param pThreadSelf The current thread.
* @param pRec The lock record.
* @param pSrcPos The source position of the locking operation.
*/
static int rtLockValidatorStackCheckLockingOrder(RTLOCKVALCLASSINT * const pClass, uint32_t const uSubClass,
PRTTHREADINT pThreadSelf, PRTLOCKVALRECUNION const pRec,
PCRTLOCKVALSRCPOS pSrcPos)
{
/*
* Some internal paranoia first.
*/
AssertPtr(pClass);
Assert(pClass->u32Magic == RTLOCKVALCLASS_MAGIC);
AssertPtr(pThreadSelf);
Assert(pThreadSelf->u32Magic == RTTHREADINT_MAGIC);
AssertPtr(pRec);
AssertPtrNull(pSrcPos);
/*
* Walk the stack, delegate problems to a worker routine.
*/
PRTLOCKVALRECUNION pCur = pThreadSelf->LockValidator.pStackTop;
if (!pCur)
return VINF_SUCCESS;
for (;;)
{
AssertPtrReturn(pCur, VERR_SEM_LV_INTERNAL_ERROR);
if (pCur->Core.u32Magic == RTLOCKVALRECNEST_MAGIC)
pCur = pCur->Nest.pDown;
else
{
uint32_t uPriorSubClass;
PRTLOCKVALRECUNION pDown;
RTLOCKVALCLASSINT *pPriorClass = rtLockValidatorRecGetClassesAndDown(pCur, &uPriorSubClass, &pDown);
if (pPriorClass != NIL_RTLOCKVALCLASS)
{
AssertPtrReturn(pPriorClass, VERR_SEM_LV_INTERNAL_ERROR);
AssertReturn(pPriorClass->u32Magic == RTLOCKVALCLASS_MAGIC, VERR_SEM_LV_INTERNAL_ERROR);
if (RT_UNLIKELY(!rtLockValidatorIsClassOrderOk(pClass, uSubClass, pPriorClass, uPriorSubClass)))
return rtLockValidatorStackCheckLockingOrder2(pClass, uSubClass, pThreadSelf, pRec, pSrcPos,
pPriorClass, pCur, pDown);
}
pCur = pDown;
}
if (!pCur)
return VINF_SUCCESS;
}
}
/**
* Check that the lock record is the topmost one on the stack, complain and fail
* if it isn't.
*
* @returns VINF_SUCCESS, VERR_SEM_LV_WRONG_RELEASE_ORDER or
* VERR_SEM_LV_INVALID_PARAMETER.
* @param pThreadSelf The current thread.
* @param pRec The record.
*/
static int rtLockValidatorStackCheckReleaseOrder(PRTTHREADINT pThreadSelf, PRTLOCKVALRECUNION pRec)
{
AssertReturn(pThreadSelf != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER);
Assert(pThreadSelf == RTThreadSelf());
PRTLOCKVALRECUNION pTop = pThreadSelf->LockValidator.pStackTop;
if (RT_LIKELY( pTop == pRec
|| ( pTop
&& pTop->Core.u32Magic == RTLOCKVALRECNEST_MAGIC
&& pTop->Nest.pRec == pRec) ))
return VINF_SUCCESS;
#ifdef RTLOCKVAL_WITH_RECURSION_RECORDS
/* Look for a recursion record so the right frame is dumped and marked. */
while (pTop)
{
if (pTop->Core.u32Magic == RTLOCKVALRECNEST_MAGIC)
{
if (pTop->Nest.pRec == pRec)
{
pRec = pTop;
break;
}
pTop = pTop->Nest.pDown;
}
else if (pTop->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC)
pTop = pTop->Excl.pDown;
else if (pTop->Core.u32Magic == RTLOCKVALRECSHRDOWN_MAGIC)
pTop = pTop->ShrdOwner.pDown;
else
break;
}
#endif
rtLockValComplainFirst("Wrong release order!", NULL, pThreadSelf, pRec, true);
rtLockValComplainPanic();
return !g_fLockValSoftWrongOrder ? VERR_SEM_LV_WRONG_RELEASE_ORDER : VINF_SUCCESS;
}
/**
* Checks if all owners are blocked - shared record operated in signaller mode.
*
* @returns true / false accordingly.
* @param pRec The record.
* @param pThreadSelf The current thread.
*/
DECL_FORCE_INLINE(bool) rtLockValidatorDdAreAllThreadsBlocked(PRTLOCKVALRECSHRD pRec, PRTTHREADINT pThreadSelf)
{
PRTLOCKVALRECSHRDOWN volatile *papOwners = pRec->papOwners;
uint32_t cAllocated = pRec->cAllocated;
uint32_t cEntries = ASMAtomicUoReadU32(&pRec->cEntries);
if (cEntries == 0)
return false;
for (uint32_t i = 0; i < cAllocated; i++)
{
PRTLOCKVALRECSHRDOWN pEntry = rtLockValidatorUoReadSharedOwner(&papOwners[i]);
if ( pEntry
&& pEntry->Core.u32Magic == RTLOCKVALRECSHRDOWN_MAGIC)
{
PRTTHREADINT pCurThread = rtLockValidatorReadThreadHandle(&pEntry->hThread);
if (!pCurThread)
return false;
if (pCurThread->u32Magic != RTTHREADINT_MAGIC)
return false;
if ( !RTTHREAD_IS_SLEEPING(rtThreadGetState(pCurThread))
&& pCurThread != pThreadSelf)
return false;
if (--cEntries == 0)
break;
}
else
Assert(!pEntry || pEntry->Core.u32Magic == RTLOCKVALRECSHRDOWN_MAGIC_DEAD);
}
return true;
}
/**
* Verifies the deadlock stack before calling it a deadlock.
*
* @retval VERR_SEM_LV_DEADLOCK if it's a deadlock.
* @retval VERR_SEM_LV_ILLEGAL_UPGRADE if it's a deadlock on the same lock.
* @retval VERR_TRY_AGAIN if something changed.
*
* @param pStack The deadlock detection stack.
* @param pThreadSelf The current thread.
*/
static int rtLockValidatorDdVerifyDeadlock(PRTLOCKVALDDSTACK pStack, PRTTHREADINT pThreadSelf)
{
uint32_t const c = pStack->c;
for (uint32_t iPass = 0; iPass < 3; iPass++)
{
for (uint32_t i = 1; i < c; i++)
{
PRTTHREADINT pThread = pStack->a[i].pThread;
if (pThread->u32Magic != RTTHREADINT_MAGIC)
return VERR_TRY_AGAIN;
if (rtThreadGetState(pThread) != pStack->a[i].enmState)
return VERR_TRY_AGAIN;
if (rtLockValidatorReadRecUnionPtr(&pThread->LockValidator.pRec) != pStack->a[i].pFirstSibling)
return VERR_TRY_AGAIN;
/* ASSUMES the signaller records won't have siblings! */
PRTLOCKVALRECUNION pRec = pStack->a[i].pRec;
if ( pRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC
&& pRec->Shared.fSignaller
&& !rtLockValidatorDdAreAllThreadsBlocked(&pRec->Shared, pThreadSelf))
return VERR_TRY_AGAIN;
}
RTThreadYield();
}
if (c == 1)
return VERR_SEM_LV_ILLEGAL_UPGRADE;
return VERR_SEM_LV_DEADLOCK;
}
/**
* Checks for stack cycles caused by another deadlock before returning.
*
* @retval VINF_SUCCESS if the stack is simply too small.
* @retval VERR_SEM_LV_EXISTING_DEADLOCK if a cycle was detected.
*
* @param pStack The deadlock detection stack.
*/
static int rtLockValidatorDdHandleStackOverflow(PRTLOCKVALDDSTACK pStack)
{
for (size_t i = 0; i < RT_ELEMENTS(pStack->a) - 1; i++)
{
PRTTHREADINT pThread = pStack->a[i].pThread;
for (size_t j = i + 1; j < RT_ELEMENTS(pStack->a); j++)
if (pStack->a[j].pThread == pThread)
return VERR_SEM_LV_EXISTING_DEADLOCK;
}
static bool volatile s_fComplained = false;
if (!s_fComplained)
{
s_fComplained = true;
rtLockValComplain(RT_SRC_POS, "lock validator stack is too small! (%zu entries)\n", RT_ELEMENTS(pStack->a));
}
return VINF_SUCCESS;
}
/**
* Worker for rtLockValidatorDeadlockDetection that does the actual deadlock
* detection.
*
* @retval VINF_SUCCESS
* @retval VERR_SEM_LV_DEADLOCK
* @retval VERR_SEM_LV_EXISTING_DEADLOCK
* @retval VERR_SEM_LV_ILLEGAL_UPGRADE
* @retval VERR_TRY_AGAIN
*
* @param pStack The stack to use.
* @param pOriginalRec The original record.
* @param pThreadSelf The calling thread.
*/
static int rtLockValidatorDdDoDetection(PRTLOCKVALDDSTACK pStack, PRTLOCKVALRECUNION const pOriginalRec,
PRTTHREADINT const pThreadSelf)
{
pStack->c = 0;
/* We could use a single RTLOCKVALDDENTRY variable here, but the
compiler may make a better job of it when using individual variables. */
PRTLOCKVALRECUNION pRec = pOriginalRec;
PRTLOCKVALRECUNION pFirstSibling = pOriginalRec;
uint32_t iEntry = UINT32_MAX;
PRTTHREADINT pThread = NIL_RTTHREAD;
RTTHREADSTATE enmState = RTTHREADSTATE_RUNNING;
for (uint32_t iLoop = 0; ; iLoop++)
{
/*
* Process the current record.
*/
RTLOCKVAL_ASSERT_PTR_ALIGN(pRec);
/* Find the next relevant owner thread and record. */
PRTLOCKVALRECUNION pNextRec = NULL;
RTTHREADSTATE enmNextState = RTTHREADSTATE_RUNNING;
PRTTHREADINT pNextThread = NIL_RTTHREAD;
switch (pRec->Core.u32Magic)
{
case RTLOCKVALRECEXCL_MAGIC:
Assert(iEntry == UINT32_MAX);
for (;;)
{
pNextThread = rtLockValidatorReadThreadHandle(&pRec->Excl.hThread);
if ( !pNextThread
|| pNextThread->u32Magic != RTTHREADINT_MAGIC)
break;
enmNextState = rtThreadGetState(pNextThread);
if ( !RTTHREAD_IS_SLEEPING(enmNextState)
&& pNextThread != pThreadSelf)
break;
pNextRec = rtLockValidatorReadRecUnionPtr(&pNextThread->LockValidator.pRec);
if (RT_LIKELY( !pNextRec
|| enmNextState == rtThreadGetState(pNextThread)))
break;
pNextRec = NULL;
}
if (!pNextRec)
{
pRec = pRec->Excl.pSibling;
if ( pRec
&& pRec != pFirstSibling)
continue;
pNextThread = NIL_RTTHREAD;
}
break;
case RTLOCKVALRECSHRD_MAGIC:
if (!pRec->Shared.fSignaller)
{
/* Skip to the next sibling if same side. ASSUMES reader priority. */
/** @todo The read side of a read-write lock is problematic if
* the implementation prioritizes writers over readers because
* that means we should could deadlock against current readers
* if a writer showed up. If the RW sem implementation is
* wrapping some native API, it's not so easy to detect when we
* should do this and when we shouldn't. Checking when we
* shouldn't is subject to wakeup scheduling and cannot easily
* be made reliable.
*
* At the moment we circumvent all this mess by declaring that
* readers has priority. This is TRUE on linux, but probably
* isn't on Solaris and FreeBSD. */
if ( pRec == pFirstSibling
&& pRec->Shared.pSibling != NULL
&& pRec->Shared.pSibling != pFirstSibling)
{
pRec = pRec->Shared.pSibling;
Assert(iEntry == UINT32_MAX);
continue;
}
}
/* Scan the owner table for blocked owners. */
if ( ASMAtomicUoReadU32(&pRec->Shared.cEntries) > 0
&& ( !pRec->Shared.fSignaller
|| iEntry != UINT32_MAX
|| rtLockValidatorDdAreAllThreadsBlocked(&pRec->Shared, pThreadSelf)
)
)
{
uint32_t cAllocated = pRec->Shared.cAllocated;
PRTLOCKVALRECSHRDOWN volatile *papOwners = pRec->Shared.papOwners;
while (++iEntry < cAllocated)
{
PRTLOCKVALRECSHRDOWN pEntry = rtLockValidatorUoReadSharedOwner(&papOwners[iEntry]);
if (pEntry)
{
for (;;)
{
if (pEntry->Core.u32Magic != RTLOCKVALRECSHRDOWN_MAGIC)
break;
pNextThread = rtLockValidatorReadThreadHandle(&pEntry->hThread);
if ( !pNextThread
|| pNextThread->u32Magic != RTTHREADINT_MAGIC)
break;
enmNextState = rtThreadGetState(pNextThread);
if ( !RTTHREAD_IS_SLEEPING(enmNextState)
&& pNextThread != pThreadSelf)
break;
pNextRec = rtLockValidatorReadRecUnionPtr(&pNextThread->LockValidator.pRec);
if (RT_LIKELY( !pNextRec
|| enmNextState == rtThreadGetState(pNextThread)))
break;
pNextRec = NULL;
}
if (pNextRec)
break;
}
else
Assert(!pEntry || pEntry->Core.u32Magic == RTLOCKVALRECSHRDOWN_MAGIC_DEAD);
}
if (pNextRec)
break;
pNextThread = NIL_RTTHREAD;
}
/* Advance to the next sibling, if any. */
pRec = pRec->Shared.pSibling;
if ( pRec != NULL
&& pRec != pFirstSibling)
{
iEntry = UINT32_MAX;
continue;
}
break;
case RTLOCKVALRECEXCL_MAGIC_DEAD:
case RTLOCKVALRECSHRD_MAGIC_DEAD:
break;
case RTLOCKVALRECSHRDOWN_MAGIC:
case RTLOCKVALRECSHRDOWN_MAGIC_DEAD:
default:
AssertMsgFailed(("%p: %#x\n", pRec, pRec->Core));
break;
}
if (pNextRec)
{
/*
* Recurse and check for deadlock.
*/
uint32_t i = pStack->c;
if (RT_UNLIKELY(i >= RT_ELEMENTS(pStack->a)))
return rtLockValidatorDdHandleStackOverflow(pStack);
pStack->c++;
pStack->a[i].pRec = pRec;
pStack->a[i].iEntry = iEntry;
pStack->a[i].enmState = enmState;
pStack->a[i].pThread = pThread;
pStack->a[i].pFirstSibling = pFirstSibling;
if (RT_UNLIKELY( pNextThread == pThreadSelf
&& ( i != 0
|| pRec->Core.u32Magic != RTLOCKVALRECSHRD_MAGIC
|| !pRec->Shared.fSignaller) /* ASSUMES signaller records have no siblings. */
)
)
return rtLockValidatorDdVerifyDeadlock(pStack, pThreadSelf);
pRec = pNextRec;
pFirstSibling = pNextRec;
iEntry = UINT32_MAX;
enmState = enmNextState;
pThread = pNextThread;
}
else
{
/*
* No deadlock here, unwind the stack and deal with any unfinished
* business there.
*/
uint32_t i = pStack->c;
for (;;)
{
/* pop */
if (i == 0)
return VINF_SUCCESS;
i--;
pRec = pStack->a[i].pRec;
iEntry = pStack->a[i].iEntry;
/* Examine it. */
uint32_t u32Magic = pRec->Core.u32Magic;
if (u32Magic == RTLOCKVALRECEXCL_MAGIC)
pRec = pRec->Excl.pSibling;
else if (u32Magic == RTLOCKVALRECSHRD_MAGIC)
{
if (iEntry + 1 < pRec->Shared.cAllocated)
break; /* continue processing this record. */
pRec = pRec->Shared.pSibling;
}
else
{
Assert( u32Magic == RTLOCKVALRECEXCL_MAGIC_DEAD
|| u32Magic == RTLOCKVALRECSHRD_MAGIC_DEAD);
continue;
}
/* Any next record to advance to? */
if ( !pRec
|| pRec == pStack->a[i].pFirstSibling)
continue;
iEntry = UINT32_MAX;
break;
}
/* Restore the rest of the state and update the stack. */
pFirstSibling = pStack->a[i].pFirstSibling;
enmState = pStack->a[i].enmState;
pThread = pStack->a[i].pThread;
pStack->c = i;
}
Assert(iLoop != 1000000);
}
}
/**
* Check for the simple no-deadlock case.
*
* @returns true if no deadlock, false if further investigation is required.
*
* @param pOriginalRec The original record.
*/
DECLINLINE(int) rtLockValidatorIsSimpleNoDeadlockCase(PRTLOCKVALRECUNION pOriginalRec)
{
if ( pOriginalRec->Excl.Core.u32Magic == RTLOCKVALRECEXCL_MAGIC
&& !pOriginalRec->Excl.pSibling)
{
PRTTHREADINT pThread = rtLockValidatorReadThreadHandle(&pOriginalRec->Excl.hThread);
if ( !pThread
|| pThread->u32Magic != RTTHREADINT_MAGIC)
return true;
RTTHREADSTATE enmState = rtThreadGetState(pThread);
if (!RTTHREAD_IS_SLEEPING(enmState))
return true;
}
return false;
}
/**
* Worker for rtLockValidatorDeadlockDetection that bitches about a deadlock.
*
* @param pStack The chain of locks causing the deadlock.
* @param pRec The record relating to the current thread's lock
* operation.
* @param pThreadSelf This thread.
* @param pSrcPos Where we are going to deadlock.
* @param rc The return code.
*/
static void rcLockValidatorDoDeadlockComplaining(PRTLOCKVALDDSTACK pStack, PRTLOCKVALRECUNION pRec,
PRTTHREADINT pThreadSelf, PCRTLOCKVALSRCPOS pSrcPos, int rc)
{
if (!ASMAtomicUoReadBool(&g_fLockValidatorQuiet))
{
const char *pszWhat;
switch (rc)
{
case VERR_SEM_LV_DEADLOCK: pszWhat = "Detected deadlock!"; break;
case VERR_SEM_LV_EXISTING_DEADLOCK: pszWhat = "Found existing deadlock!"; break;
case VERR_SEM_LV_ILLEGAL_UPGRADE: pszWhat = "Illegal lock upgrade!"; break;
default: AssertFailed(); pszWhat = "!unexpected rc!"; break;
}
rtLockValComplainFirst(pszWhat, pSrcPos, pThreadSelf, pStack->a[0].pRec != pRec ? pRec : NULL, true);
rtLockValComplainMore("---- start of deadlock chain - %u entries ----\n", pStack->c);
for (uint32_t i = 0; i < pStack->c; i++)
{
char szPrefix[24];
RTStrPrintf(szPrefix, sizeof(szPrefix), "#%02u: ", i);
PRTLOCKVALRECUNION pShrdOwner = NULL;
if (pStack->a[i].pRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC)
pShrdOwner = (PRTLOCKVALRECUNION)pStack->a[i].pRec->Shared.papOwners[pStack->a[i].iEntry];
if (VALID_PTR(pShrdOwner) && pShrdOwner->Core.u32Magic == RTLOCKVALRECSHRDOWN_MAGIC)
{
rtLockValComplainAboutLock(szPrefix, pShrdOwner, "\n");
rtLockValComplainAboutLockStack(pShrdOwner->ShrdOwner.hThread, 5, 2, pShrdOwner);
}
else
{
rtLockValComplainAboutLock(szPrefix, pStack->a[i].pRec, "\n");
if (pStack->a[i].pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC)
rtLockValComplainAboutLockStack(pStack->a[i].pRec->Excl.hThread, 5, 2, pStack->a[i].pRec);
}
}
rtLockValComplainMore("---- end of deadlock chain ----\n");
}
rtLockValComplainPanic();
}
/**
* Perform deadlock detection.
*
* @retval VINF_SUCCESS
* @retval VERR_SEM_LV_DEADLOCK
* @retval VERR_SEM_LV_EXISTING_DEADLOCK
* @retval VERR_SEM_LV_ILLEGAL_UPGRADE
*
* @param pRec The record relating to the current thread's lock
* operation.
* @param pThreadSelf The current thread.
* @param pSrcPos The position of the current lock operation.
*/
static int rtLockValidatorDeadlockDetection(PRTLOCKVALRECUNION pRec, PRTTHREADINT pThreadSelf, PCRTLOCKVALSRCPOS pSrcPos)
{
RTLOCKVALDDSTACK Stack;
int rc = rtLockValidatorDdDoDetection(&Stack, pRec, pThreadSelf);
if (RT_SUCCESS(rc))
return VINF_SUCCESS;
if (rc == VERR_TRY_AGAIN)
{
for (uint32_t iLoop = 0; ; iLoop++)
{
rc = rtLockValidatorDdDoDetection(&Stack, pRec, pThreadSelf);
if (RT_SUCCESS_NP(rc))
return VINF_SUCCESS;
if (rc != VERR_TRY_AGAIN)
break;
RTThreadYield();
if (iLoop >= 3)
return VINF_SUCCESS;
}
}
rcLockValidatorDoDeadlockComplaining(&Stack, pRec, pThreadSelf, pSrcPos, rc);
return rc;
}
RTDECL(void) RTLockValidatorRecExclInitV(PRTLOCKVALRECEXCL pRec, RTLOCKVALCLASS hClass, uint32_t uSubClass,
void *hLock, bool fEnabled, const char *pszNameFmt, va_list va)
{
RTLOCKVAL_ASSERT_PTR_ALIGN(pRec);
RTLOCKVAL_ASSERT_PTR_ALIGN(hLock);
Assert( uSubClass >= RTLOCKVAL_SUB_CLASS_USER
|| uSubClass == RTLOCKVAL_SUB_CLASS_NONE
|| uSubClass == RTLOCKVAL_SUB_CLASS_ANY);
pRec->Core.u32Magic = RTLOCKVALRECEXCL_MAGIC;
pRec->fEnabled = fEnabled && RTLockValidatorIsEnabled();
pRec->afReserved[0] = 0;
pRec->afReserved[1] = 0;
pRec->afReserved[2] = 0;
rtLockValidatorSrcPosInit(&pRec->SrcPos);
pRec->hThread = NIL_RTTHREAD;
pRec->pDown = NULL;
pRec->hClass = rtLockValidatorClassValidateAndRetain(hClass);
pRec->uSubClass = uSubClass;
pRec->cRecursion = 0;
pRec->hLock = hLock;
pRec->pSibling = NULL;
if (pszNameFmt)
RTStrPrintfV(pRec->szName, sizeof(pRec->szName), pszNameFmt, va);
else
{
static uint32_t volatile s_cAnonymous = 0;
uint32_t i = ASMAtomicIncU32(&s_cAnonymous) - 1;
RTStrPrintf(pRec->szName, sizeof(pRec->szName), "anon-excl-%u", i);
}
/* Lazy initialization. */
if (RT_UNLIKELY(g_hLockValidatorXRoads == NIL_RTSEMXROADS))
rtLockValidatorLazyInit();
}
RTDECL(void) RTLockValidatorRecExclInit(PRTLOCKVALRECEXCL pRec, RTLOCKVALCLASS hClass, uint32_t uSubClass,
void *hLock, bool fEnabled, const char *pszNameFmt, ...)
{
va_list va;
va_start(va, pszNameFmt);
RTLockValidatorRecExclInitV(pRec, hClass, uSubClass, hLock, fEnabled, pszNameFmt, va);
va_end(va);
}
RTDECL(int) RTLockValidatorRecExclCreateV(PRTLOCKVALRECEXCL *ppRec, RTLOCKVALCLASS hClass,
uint32_t uSubClass, void *pvLock, bool fEnabled,
const char *pszNameFmt, va_list va)
{
PRTLOCKVALRECEXCL pRec;
*ppRec = pRec = (PRTLOCKVALRECEXCL)RTMemAlloc(sizeof(*pRec));
if (!pRec)
return VERR_NO_MEMORY;
RTLockValidatorRecExclInitV(pRec, hClass, uSubClass, pvLock, fEnabled, pszNameFmt, va);
return VINF_SUCCESS;
}
RTDECL(int) RTLockValidatorRecExclCreate(PRTLOCKVALRECEXCL *ppRec, RTLOCKVALCLASS hClass,
uint32_t uSubClass, void *pvLock, bool fEnabled,
const char *pszNameFmt, ...)
{
va_list va;
va_start(va, pszNameFmt);
int rc = RTLockValidatorRecExclCreateV(ppRec, hClass, uSubClass, pvLock, fEnabled, pszNameFmt, va);
va_end(va);
return rc;
}
RTDECL(void) RTLockValidatorRecExclDelete(PRTLOCKVALRECEXCL pRec)
{
Assert(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC);
rtLockValidatorSerializeDestructEnter();
ASMAtomicWriteU32(&pRec->Core.u32Magic, RTLOCKVALRECEXCL_MAGIC_DEAD);
ASMAtomicWriteHandle(&pRec->hThread, NIL_RTTHREAD);
RTLOCKVALCLASS hClass;
ASMAtomicXchgHandle(&pRec->hClass, NIL_RTLOCKVALCLASS, &hClass);
if (pRec->pSibling)
rtLockValidatorUnlinkAllSiblings(&pRec->Core);
rtLockValidatorSerializeDestructLeave();
if (hClass != NIL_RTLOCKVALCLASS)
RTLockValidatorClassRelease(hClass);
}
RTDECL(void) RTLockValidatorRecExclDestroy(PRTLOCKVALRECEXCL *ppRec)
{
PRTLOCKVALRECEXCL pRec = *ppRec;
*ppRec = NULL;
if (pRec)
{
RTLockValidatorRecExclDelete(pRec);
RTMemFree(pRec);
}
}
RTDECL(uint32_t) RTLockValidatorRecExclSetSubClass(PRTLOCKVALRECEXCL pRec, uint32_t uSubClass)
{
AssertPtrReturn(pRec, RTLOCKVAL_SUB_CLASS_INVALID);
AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, RTLOCKVAL_SUB_CLASS_INVALID);
AssertReturn( uSubClass >= RTLOCKVAL_SUB_CLASS_USER
|| uSubClass == RTLOCKVAL_SUB_CLASS_NONE
|| uSubClass == RTLOCKVAL_SUB_CLASS_ANY,
RTLOCKVAL_SUB_CLASS_INVALID);
return ASMAtomicXchgU32(&pRec->uSubClass, uSubClass);
}
RTDECL(void) RTLockValidatorRecExclSetOwner(PRTLOCKVALRECEXCL pRec, RTTHREAD hThreadSelf,
PCRTLOCKVALSRCPOS pSrcPos, bool fFirstRecursion)
{
PRTLOCKVALRECUNION pRecU = (PRTLOCKVALRECUNION)pRec;
if (!pRecU)
return;
AssertReturnVoid(pRecU->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC);
if (!pRecU->Excl.fEnabled)
return;
if (hThreadSelf == NIL_RTTHREAD)
{
hThreadSelf = RTThreadSelfAutoAdopt();
AssertReturnVoid(hThreadSelf != NIL_RTTHREAD);
}
AssertReturnVoid(hThreadSelf->u32Magic == RTTHREADINT_MAGIC);
Assert(hThreadSelf == RTThreadSelf());
ASMAtomicIncS32(&hThreadSelf->LockValidator.cWriteLocks);
if (pRecU->Excl.hThread == hThreadSelf)
{
Assert(!fFirstRecursion);
pRecU->Excl.cRecursion++;
rtLockValidatorStackPushRecursion(hThreadSelf, pRecU, pSrcPos);
}
else
{
Assert(pRecU->Excl.hThread == NIL_RTTHREAD);
rtLockValidatorSrcPosCopy(&pRecU->Excl.SrcPos, pSrcPos);
ASMAtomicUoWriteU32(&pRecU->Excl.cRecursion, 1);
ASMAtomicWriteHandle(&pRecU->Excl.hThread, hThreadSelf);
rtLockValidatorStackPush(hThreadSelf, pRecU);
}
}
/**
* Internal worker for RTLockValidatorRecExclReleaseOwner and
* RTLockValidatorRecExclReleaseOwnerUnchecked.
*/
static void rtLockValidatorRecExclReleaseOwnerUnchecked(PRTLOCKVALRECUNION pRec, bool fFinalRecursion)
{
RTTHREADINT *pThread = pRec->Excl.hThread;
AssertReturnVoid(pThread != NIL_RTTHREAD);
Assert(pThread == RTThreadSelf());
ASMAtomicDecS32(&pThread->LockValidator.cWriteLocks);
uint32_t c = ASMAtomicDecU32(&pRec->Excl.cRecursion);
if (c == 0)
{
rtLockValidatorStackPop(pThread, pRec);
ASMAtomicWriteHandle(&pRec->Excl.hThread, NIL_RTTHREAD);
}
else
{
Assert(c < UINT32_C(0xffff0000));
Assert(!fFinalRecursion);
rtLockValidatorStackPopRecursion(pThread, pRec);
}
}
RTDECL(int) RTLockValidatorRecExclReleaseOwner(PRTLOCKVALRECEXCL pRec, bool fFinalRecursion)
{
PRTLOCKVALRECUNION pRecU = (PRTLOCKVALRECUNION)pRec;
if (!pRecU)
return VINF_SUCCESS;
AssertReturn(pRecU->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
if (!pRecU->Excl.fEnabled)
return VINF_SUCCESS;
/*
* Check the release order.
*/
if ( pRecU->Excl.hClass != NIL_RTLOCKVALCLASS
&& pRecU->Excl.hClass->fStrictReleaseOrder
&& pRecU->Excl.hClass->cMsMinOrder != RT_INDEFINITE_WAIT
)
{
int rc = rtLockValidatorStackCheckReleaseOrder(pRecU->Excl.hThread, pRecU);
if (RT_FAILURE(rc))
return rc;
}
/*
* Join paths with RTLockValidatorRecExclReleaseOwnerUnchecked.
*/
rtLockValidatorRecExclReleaseOwnerUnchecked(pRecU, fFinalRecursion);
return VINF_SUCCESS;
}
RTDECL(void) RTLockValidatorRecExclReleaseOwnerUnchecked(PRTLOCKVALRECEXCL pRec)
{
PRTLOCKVALRECUNION pRecU = (PRTLOCKVALRECUNION)pRec;
AssertReturnVoid(pRecU->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC);
if (pRecU->Excl.fEnabled)
rtLockValidatorRecExclReleaseOwnerUnchecked(pRecU, false);
}
RTDECL(int) RTLockValidatorRecExclRecursion(PRTLOCKVALRECEXCL pRec, PCRTLOCKVALSRCPOS pSrcPos)
{
PRTLOCKVALRECUNION pRecU = (PRTLOCKVALRECUNION)pRec;
if (!pRecU)
return VINF_SUCCESS;
AssertReturn(pRecU->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
if (!pRecU->Excl.fEnabled)
return VINF_SUCCESS;
AssertReturn(pRecU->Excl.hThread != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER);
AssertReturn(pRecU->Excl.cRecursion > 0, VERR_SEM_LV_INVALID_PARAMETER);
if ( pRecU->Excl.hClass != NIL_RTLOCKVALCLASS
&& !pRecU->Excl.hClass->fRecursionOk)
{
rtLockValComplainFirst("Recursion not allowed by the class!",
pSrcPos, pRecU->Excl.hThread, (PRTLOCKVALRECUNION)pRec, true);
rtLockValComplainPanic();
return VERR_SEM_LV_NESTED;
}
Assert(pRecU->Excl.cRecursion < _1M);
pRecU->Excl.cRecursion++;
rtLockValidatorStackPushRecursion(pRecU->Excl.hThread, pRecU, pSrcPos);
return VINF_SUCCESS;
}
RTDECL(int) RTLockValidatorRecExclUnwind(PRTLOCKVALRECEXCL pRec)
{
PRTLOCKVALRECUNION pRecU = (PRTLOCKVALRECUNION)pRec;
AssertReturn(pRecU->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
if (!pRecU->Excl.fEnabled)
return VINF_SUCCESS;
AssertReturn(pRecU->Excl.hThread != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER);
Assert(pRecU->Excl.hThread == RTThreadSelf());
AssertReturn(pRecU->Excl.cRecursion > 1, VERR_SEM_LV_INVALID_PARAMETER);
/*
* Check the release order.
*/
if ( pRecU->Excl.hClass != NIL_RTLOCKVALCLASS
&& pRecU->Excl.hClass->fStrictReleaseOrder
&& pRecU->Excl.hClass->cMsMinOrder != RT_INDEFINITE_WAIT
)
{
int rc = rtLockValidatorStackCheckReleaseOrder(pRecU->Excl.hThread, pRecU);
if (RT_FAILURE(rc))
return rc;
}
/*
* Perform the unwind.
*/
pRecU->Excl.cRecursion--;
rtLockValidatorStackPopRecursion(pRecU->Excl.hThread, pRecU);
return VINF_SUCCESS;
}
RTDECL(int) RTLockValidatorRecExclRecursionMixed(PRTLOCKVALRECEXCL pRec, PRTLOCKVALRECCORE pRecMixed, PCRTLOCKVALSRCPOS pSrcPos)
{
PRTLOCKVALRECUNION pRecU = (PRTLOCKVALRECUNION)pRec;
AssertReturn(pRecU->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
PRTLOCKVALRECUNION pRecMixedU = (PRTLOCKVALRECUNION)pRecMixed;
AssertReturn( pRecMixedU->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC
|| pRecMixedU->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC
, VERR_SEM_LV_INVALID_PARAMETER);
if (!pRecU->Excl.fEnabled)
return VINF_SUCCESS;
Assert(pRecU->Excl.hThread == RTThreadSelf());
AssertReturn(pRecU->Excl.hThread != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER);
AssertReturn(pRecU->Excl.cRecursion > 0, VERR_SEM_LV_INVALID_PARAMETER);
if ( pRecU->Excl.hClass != NIL_RTLOCKVALCLASS
&& !pRecU->Excl.hClass->fRecursionOk)
{
rtLockValComplainFirst("Mixed recursion not allowed by the class!",
pSrcPos, pRecU->Excl.hThread, (PRTLOCKVALRECUNION)pRec, true);
rtLockValComplainPanic();
return VERR_SEM_LV_NESTED;
}
Assert(pRecU->Excl.cRecursion < _1M);
pRecU->Excl.cRecursion++;
rtLockValidatorStackPushRecursion(pRecU->Excl.hThread, pRecU, pSrcPos);
return VINF_SUCCESS;
}
RTDECL(int) RTLockValidatorRecExclUnwindMixed(PRTLOCKVALRECEXCL pRec, PRTLOCKVALRECCORE pRecMixed)
{
PRTLOCKVALRECUNION pRecU = (PRTLOCKVALRECUNION)pRec;
AssertReturn(pRecU->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
PRTLOCKVALRECUNION pRecMixedU = (PRTLOCKVALRECUNION)pRecMixed;
AssertReturn( pRecMixedU->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC
|| pRecMixedU->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC
, VERR_SEM_LV_INVALID_PARAMETER);
if (!pRecU->Excl.fEnabled)
return VINF_SUCCESS;
Assert(pRecU->Excl.hThread == RTThreadSelf());
AssertReturn(pRecU->Excl.hThread != NIL_RTTHREAD, VERR_SEM_LV_INVALID_PARAMETER);
AssertReturn(pRecU->Excl.cRecursion > 1, VERR_SEM_LV_INVALID_PARAMETER);
/*
* Check the release order.
*/
if ( pRecU->Excl.hClass != NIL_RTLOCKVALCLASS
&& pRecU->Excl.hClass->fStrictReleaseOrder
&& pRecU->Excl.hClass->cMsMinOrder != RT_INDEFINITE_WAIT
)
{
int rc = rtLockValidatorStackCheckReleaseOrder(pRecU->Excl.hThread, pRecU);
if (RT_FAILURE(rc))
return rc;
}
/*
* Perform the unwind.
*/
pRecU->Excl.cRecursion--;
rtLockValidatorStackPopRecursion(pRecU->Excl.hThread, pRecU);
return VINF_SUCCESS;
}
RTDECL(int) RTLockValidatorRecExclCheckOrder(PRTLOCKVALRECEXCL pRec, RTTHREAD hThreadSelf,
PCRTLOCKVALSRCPOS pSrcPos, RTMSINTERVAL cMillies)
{
/*
* Validate and adjust input. Quit early if order validation is disabled.
*/
PRTLOCKVALRECUNION pRecU = (PRTLOCKVALRECUNION)pRec;
if (!pRecU)
return VINF_SUCCESS;
AssertReturn(pRecU->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
if ( !pRecU->Excl.fEnabled
|| pRecU->Excl.hClass == NIL_RTLOCKVALCLASS
|| pRecU->Excl.hClass->cMsMinOrder == RT_INDEFINITE_WAIT
|| pRecU->Excl.hClass->cMsMinOrder > cMillies)
return VINF_SUCCESS;
if (hThreadSelf == NIL_RTTHREAD)
{
hThreadSelf = RTThreadSelfAutoAdopt();
AssertReturn(hThreadSelf != NIL_RTTHREAD, VERR_SEM_LV_INTERNAL_ERROR);
}
AssertReturn(hThreadSelf->u32Magic == RTTHREADINT_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
Assert(hThreadSelf == RTThreadSelf());
/*
* Detect recursion as it isn't subject to order restrictions.
*/
if (pRec->hThread == hThreadSelf)
return VINF_SUCCESS;
return rtLockValidatorStackCheckLockingOrder(pRecU->Excl.hClass, pRecU->Excl.uSubClass, hThreadSelf, pRecU, pSrcPos);
}
RTDECL(int) RTLockValidatorRecExclCheckBlocking(PRTLOCKVALRECEXCL pRec, RTTHREAD hThreadSelf,
PCRTLOCKVALSRCPOS pSrcPos, bool fRecursiveOk, RTMSINTERVAL cMillies,
RTTHREADSTATE enmSleepState, bool fReallySleeping)
{
/*
* Fend off wild life.
*/
PRTLOCKVALRECUNION pRecU = (PRTLOCKVALRECUNION)pRec;
if (!pRecU)
return VINF_SUCCESS;
AssertPtrReturn(pRecU, VERR_SEM_LV_INVALID_PARAMETER);
AssertReturn(pRecU->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
if (!pRec->fEnabled)
return VINF_SUCCESS;
PRTTHREADINT pThreadSelf = hThreadSelf;
AssertPtrReturn(pThreadSelf, VERR_SEM_LV_INVALID_PARAMETER);
AssertReturn(pThreadSelf->u32Magic == RTTHREADINT_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
Assert(pThreadSelf == RTThreadSelf());
AssertReturn(RTTHREAD_IS_SLEEPING(enmSleepState), VERR_SEM_LV_INVALID_PARAMETER);
RTTHREADSTATE enmThreadState = rtThreadGetState(pThreadSelf);
if (RT_UNLIKELY(enmThreadState != RTTHREADSTATE_RUNNING))
{
AssertReturn( enmThreadState == RTTHREADSTATE_TERMINATED /* rtThreadRemove uses locks too */
|| enmThreadState == RTTHREADSTATE_INITIALIZING /* rtThreadInsert uses locks too */
, VERR_SEM_LV_INVALID_PARAMETER);
enmSleepState = enmThreadState;
}
/*
* Record the location.
*/
rtLockValidatorWriteRecUnionPtr(&pThreadSelf->LockValidator.pRec, pRecU);
rtLockValidatorSrcPosCopy(&pThreadSelf->LockValidator.SrcPos, pSrcPos);
ASMAtomicWriteBool(&pThreadSelf->LockValidator.fInValidator, true);
pThreadSelf->LockValidator.enmRecState = enmSleepState;
rtThreadSetState(pThreadSelf, enmSleepState);
/*
* Don't do deadlock detection if we're recursing.
*
* On some hosts we don't do recursion accounting our selves and there
* isn't any other place to check for this.
*/
int rc = VINF_SUCCESS;
if (rtLockValidatorReadThreadHandle(&pRecU->Excl.hThread) == pThreadSelf)
{
if ( !fRecursiveOk
|| ( pRecU->Excl.hClass != NIL_RTLOCKVALCLASS
&& !pRecU->Excl.hClass->fRecursionOk))
{
rtLockValComplainFirst("Recursion not allowed!", pSrcPos, pThreadSelf, pRecU, true);
rtLockValComplainPanic();
rc = VERR_SEM_LV_NESTED;
}
}
/*
* Perform deadlock detection.
*/
else if ( pRecU->Excl.hClass != NIL_RTLOCKVALCLASS
&& ( pRecU->Excl.hClass->cMsMinDeadlock > cMillies
|| pRecU->Excl.hClass->cMsMinDeadlock > RT_INDEFINITE_WAIT))
rc = VINF_SUCCESS;
else if (!rtLockValidatorIsSimpleNoDeadlockCase(pRecU))
rc = rtLockValidatorDeadlockDetection(pRecU, pThreadSelf, pSrcPos);
if (RT_SUCCESS(rc))
ASMAtomicWriteBool(&pThreadSelf->fReallySleeping, fReallySleeping);
else
{
rtThreadSetState(pThreadSelf, enmThreadState);
rtLockValidatorWriteRecUnionPtr(&pThreadSelf->LockValidator.pRec, NULL);
}
ASMAtomicWriteBool(&pThreadSelf->LockValidator.fInValidator, false);
return rc;
}
RT_EXPORT_SYMBOL(RTLockValidatorRecExclCheckBlocking);
RTDECL(int) RTLockValidatorRecExclCheckOrderAndBlocking(PRTLOCKVALRECEXCL pRec, RTTHREAD hThreadSelf,
PCRTLOCKVALSRCPOS pSrcPos, bool fRecursiveOk, RTMSINTERVAL cMillies,
RTTHREADSTATE enmSleepState, bool fReallySleeping)
{
int rc = RTLockValidatorRecExclCheckOrder(pRec, hThreadSelf, pSrcPos, cMillies);
if (RT_SUCCESS(rc))
rc = RTLockValidatorRecExclCheckBlocking(pRec, hThreadSelf, pSrcPos, fRecursiveOk, cMillies,
enmSleepState, fReallySleeping);
return rc;
}
RT_EXPORT_SYMBOL(RTLockValidatorRecExclCheckOrderAndBlocking);
RTDECL(void) RTLockValidatorRecSharedInitV(PRTLOCKVALRECSHRD pRec, RTLOCKVALCLASS hClass, uint32_t uSubClass,
void *hLock, bool fSignaller, bool fEnabled, const char *pszNameFmt, va_list va)
{
RTLOCKVAL_ASSERT_PTR_ALIGN(pRec);
RTLOCKVAL_ASSERT_PTR_ALIGN(hLock);
Assert( uSubClass >= RTLOCKVAL_SUB_CLASS_USER
|| uSubClass == RTLOCKVAL_SUB_CLASS_NONE
|| uSubClass == RTLOCKVAL_SUB_CLASS_ANY);
pRec->Core.u32Magic = RTLOCKVALRECSHRD_MAGIC;
pRec->uSubClass = uSubClass;
pRec->hClass = rtLockValidatorClassValidateAndRetain(hClass);
pRec->hLock = hLock;
pRec->fEnabled = fEnabled && RTLockValidatorIsEnabled();
pRec->fSignaller = fSignaller;
pRec->pSibling = NULL;
/* the table */
pRec->cEntries = 0;
pRec->iLastEntry = 0;
pRec->cAllocated = 0;
pRec->fReallocating = false;
pRec->fPadding = false;
pRec->papOwners = NULL;
/* the name */
if (pszNameFmt)
RTStrPrintfV(pRec->szName, sizeof(pRec->szName), pszNameFmt, va);
else
{
static uint32_t volatile s_cAnonymous = 0;
uint32_t i = ASMAtomicIncU32(&s_cAnonymous) - 1;
RTStrPrintf(pRec->szName, sizeof(pRec->szName), "anon-shrd-%u", i);
}
}
RTDECL(void) RTLockValidatorRecSharedInit(PRTLOCKVALRECSHRD pRec, RTLOCKVALCLASS hClass, uint32_t uSubClass,
void *hLock, bool fSignaller, bool fEnabled, const char *pszNameFmt, ...)
{
va_list va;
va_start(va, pszNameFmt);
RTLockValidatorRecSharedInitV(pRec, hClass, uSubClass, hLock, fSignaller, fEnabled, pszNameFmt, va);
va_end(va);
}
RTDECL(int) RTLockValidatorRecSharedCreateV(PRTLOCKVALRECSHRD *ppRec, RTLOCKVALCLASS hClass,
uint32_t uSubClass, void *pvLock, bool fSignaller, bool fEnabled,
const char *pszNameFmt, va_list va)
{
PRTLOCKVALRECSHRD pRec;
*ppRec = pRec = (PRTLOCKVALRECSHRD)RTMemAlloc(sizeof(*pRec));
if (!pRec)
return VERR_NO_MEMORY;
RTLockValidatorRecSharedInitV(pRec, hClass, uSubClass, pvLock, fSignaller, fEnabled, pszNameFmt, va);
return VINF_SUCCESS;
}
RTDECL(int) RTLockValidatorRecSharedCreate(PRTLOCKVALRECSHRD *ppRec, RTLOCKVALCLASS hClass,
uint32_t uSubClass, void *pvLock, bool fSignaller, bool fEnabled,
const char *pszNameFmt, ...)
{
va_list va;
va_start(va, pszNameFmt);
int rc = RTLockValidatorRecSharedCreateV(ppRec, hClass, uSubClass, pvLock, fSignaller, fEnabled, pszNameFmt, va);
va_end(va);
return rc;
}
RTDECL(void) RTLockValidatorRecSharedDelete(PRTLOCKVALRECSHRD pRec)
{
Assert(pRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC);
/*
* Flip it into table realloc mode and take the destruction lock.
*/
rtLockValidatorSerializeDestructEnter();
while (!ASMAtomicCmpXchgBool(&pRec->fReallocating, true, false))
{
rtLockValidatorSerializeDestructLeave();
rtLockValidatorSerializeDetectionEnter();
rtLockValidatorSerializeDetectionLeave();
rtLockValidatorSerializeDestructEnter();
}
ASMAtomicWriteU32(&pRec->Core.u32Magic, RTLOCKVALRECSHRD_MAGIC_DEAD);
RTLOCKVALCLASS hClass;
ASMAtomicXchgHandle(&pRec->hClass, NIL_RTLOCKVALCLASS, &hClass);
if (pRec->papOwners)
{
PRTLOCKVALRECSHRDOWN volatile *papOwners = pRec->papOwners;
ASMAtomicUoWriteNullPtr(&pRec->papOwners);
ASMAtomicUoWriteU32(&pRec->cAllocated, 0);
RTMemFree((void *)papOwners);
}
if (pRec->pSibling)
rtLockValidatorUnlinkAllSiblings(&pRec->Core);
ASMAtomicWriteBool(&pRec->fReallocating, false);
rtLockValidatorSerializeDestructLeave();
if (hClass != NIL_RTLOCKVALCLASS)
RTLockValidatorClassRelease(hClass);
}
RTDECL(void) RTLockValidatorRecSharedDestroy(PRTLOCKVALRECSHRD *ppRec)
{
PRTLOCKVALRECSHRD pRec = *ppRec;
*ppRec = NULL;
if (pRec)
{
RTLockValidatorRecSharedDelete(pRec);
RTMemFree(pRec);
}
}
RTDECL(uint32_t) RTLockValidatorRecSharedSetSubClass(PRTLOCKVALRECSHRD pRec, uint32_t uSubClass)
{
AssertPtrReturn(pRec, RTLOCKVAL_SUB_CLASS_INVALID);
AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC, RTLOCKVAL_SUB_CLASS_INVALID);
AssertReturn( uSubClass >= RTLOCKVAL_SUB_CLASS_USER
|| uSubClass == RTLOCKVAL_SUB_CLASS_NONE
|| uSubClass == RTLOCKVAL_SUB_CLASS_ANY,
RTLOCKVAL_SUB_CLASS_INVALID);
return ASMAtomicXchgU32(&pRec->uSubClass, uSubClass);
}
/**
* Locates an owner (thread) in a shared lock record.
*
* @returns Pointer to the owner entry on success, NULL on failure..
* @param pShared The shared lock record.
* @param hThread The thread (owner) to find.
* @param piEntry Where to optionally return the table in index.
* Optional.
*/
DECLINLINE(PRTLOCKVALRECUNION)
rtLockValidatorRecSharedFindOwner(PRTLOCKVALRECSHRD pShared, RTTHREAD hThread, uint32_t *piEntry)
{
rtLockValidatorSerializeDetectionEnter();
PRTLOCKVALRECSHRDOWN volatile *papOwners = pShared->papOwners;
if (papOwners)
{
uint32_t const cMax = pShared->cAllocated;
for (uint32_t iEntry = 0; iEntry < cMax; iEntry++)
{
PRTLOCKVALRECUNION pEntry = (PRTLOCKVALRECUNION)rtLockValidatorUoReadSharedOwner(&papOwners[iEntry]);
if (pEntry && pEntry->ShrdOwner.hThread == hThread)
{
rtLockValidatorSerializeDetectionLeave();
if (piEntry)
*piEntry = iEntry;
return pEntry;
}
}
}
rtLockValidatorSerializeDetectionLeave();
return NULL;
}
RTDECL(int) RTLockValidatorRecSharedCheckOrder(PRTLOCKVALRECSHRD pRec, RTTHREAD hThreadSelf,
PCRTLOCKVALSRCPOS pSrcPos, RTMSINTERVAL cMillies)
{
/*
* Validate and adjust input. Quit early if order validation is disabled.
*/
PRTLOCKVALRECUNION pRecU = (PRTLOCKVALRECUNION)pRec;
AssertReturn(pRecU->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
if ( !pRecU->Shared.fEnabled
|| pRecU->Shared.hClass == NIL_RTLOCKVALCLASS
|| pRecU->Shared.hClass->cMsMinOrder == RT_INDEFINITE_WAIT
|| pRecU->Shared.hClass->cMsMinOrder > cMillies
)
return VINF_SUCCESS;
if (hThreadSelf == NIL_RTTHREAD)
{
hThreadSelf = RTThreadSelfAutoAdopt();
AssertReturn(hThreadSelf != NIL_RTTHREAD, VERR_SEM_LV_INTERNAL_ERROR);
}
AssertReturn(hThreadSelf->u32Magic == RTTHREADINT_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
Assert(hThreadSelf == RTThreadSelf());
/*
* Detect recursion as it isn't subject to order restrictions.
*/
PRTLOCKVALRECUNION pEntry = rtLockValidatorRecSharedFindOwner(&pRecU->Shared, hThreadSelf, NULL);
if (pEntry)
return VINF_SUCCESS;
return rtLockValidatorStackCheckLockingOrder(pRecU->Shared.hClass, pRecU->Shared.uSubClass, hThreadSelf, pRecU, pSrcPos);
}
RTDECL(int) RTLockValidatorRecSharedCheckBlocking(PRTLOCKVALRECSHRD pRec, RTTHREAD hThreadSelf,
PCRTLOCKVALSRCPOS pSrcPos, bool fRecursiveOk, RTMSINTERVAL cMillies,
RTTHREADSTATE enmSleepState, bool fReallySleeping)
{
/*
* Fend off wild life.
*/
PRTLOCKVALRECUNION pRecU = (PRTLOCKVALRECUNION)pRec;
AssertPtrReturn(pRecU, VERR_SEM_LV_INVALID_PARAMETER);
AssertReturn(pRecU->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
if (!pRecU->Shared.fEnabled)
return VINF_SUCCESS;
PRTTHREADINT pThreadSelf = hThreadSelf;
AssertPtrReturn(pThreadSelf, VERR_SEM_LV_INVALID_PARAMETER);
AssertReturn(pThreadSelf->u32Magic == RTTHREADINT_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
Assert(pThreadSelf == RTThreadSelf());
AssertReturn(RTTHREAD_IS_SLEEPING(enmSleepState), VERR_SEM_LV_INVALID_PARAMETER);
RTTHREADSTATE enmThreadState = rtThreadGetState(pThreadSelf);
if (RT_UNLIKELY(enmThreadState != RTTHREADSTATE_RUNNING))
{
AssertReturn( enmThreadState == RTTHREADSTATE_TERMINATED /* rtThreadRemove uses locks too */
|| enmThreadState == RTTHREADSTATE_INITIALIZING /* rtThreadInsert uses locks too */
, VERR_SEM_LV_INVALID_PARAMETER);
enmSleepState = enmThreadState;
}
/*
* Record the location.
*/
rtLockValidatorWriteRecUnionPtr(&pThreadSelf->LockValidator.pRec, pRecU);
rtLockValidatorSrcPosCopy(&pThreadSelf->LockValidator.SrcPos, pSrcPos);
ASMAtomicWriteBool(&pThreadSelf->LockValidator.fInValidator, true);
pThreadSelf->LockValidator.enmRecState = enmSleepState;
rtThreadSetState(pThreadSelf, enmSleepState);
/*
* Don't do deadlock detection if we're recursing.
*/
int rc = VINF_SUCCESS;
PRTLOCKVALRECUNION pEntry = !pRecU->Shared.fSignaller
? rtLockValidatorRecSharedFindOwner(&pRecU->Shared, pThreadSelf, NULL)
: NULL;
if (pEntry)
{
if ( !fRecursiveOk
|| ( pRec->hClass
&& !pRec->hClass->fRecursionOk)
)
{
rtLockValComplainFirst("Recursion not allowed!", pSrcPos, pThreadSelf, pRecU, true);
rtLockValComplainPanic();
rc = VERR_SEM_LV_NESTED;
}
}
/*
* Perform deadlock detection.
*/
else if ( pRec->hClass
&& ( pRec->hClass->cMsMinDeadlock == RT_INDEFINITE_WAIT
|| pRec->hClass->cMsMinDeadlock > cMillies))
rc = VINF_SUCCESS;
else if (!rtLockValidatorIsSimpleNoDeadlockCase(pRecU))
rc = rtLockValidatorDeadlockDetection(pRecU, pThreadSelf, pSrcPos);
if (RT_SUCCESS(rc))
ASMAtomicWriteBool(&pThreadSelf->fReallySleeping, fReallySleeping);
else
{
rtThreadSetState(pThreadSelf, enmThreadState);
rtLockValidatorWriteRecUnionPtr(&pThreadSelf->LockValidator.pRec, NULL);
}
ASMAtomicWriteBool(&pThreadSelf->LockValidator.fInValidator, false);
return rc;
}
RT_EXPORT_SYMBOL(RTLockValidatorRecSharedCheckBlocking);
RTDECL(int) RTLockValidatorRecSharedCheckOrderAndBlocking(PRTLOCKVALRECSHRD pRec, RTTHREAD hThreadSelf,
PCRTLOCKVALSRCPOS pSrcPos, bool fRecursiveOk, RTMSINTERVAL cMillies,
RTTHREADSTATE enmSleepState, bool fReallySleeping)
{
int rc = RTLockValidatorRecSharedCheckOrder(pRec, hThreadSelf, pSrcPos, cMillies);
if (RT_SUCCESS(rc))
rc = RTLockValidatorRecSharedCheckBlocking(pRec, hThreadSelf, pSrcPos, fRecursiveOk, cMillies,
enmSleepState, fReallySleeping);
return rc;
}
RT_EXPORT_SYMBOL(RTLockValidatorRecSharedCheckOrderAndBlocking);
/**
* Allocates and initializes an owner entry for the shared lock record.
*
* @returns The new owner entry.
* @param pRec The shared lock record.
* @param pThreadSelf The calling thread and owner. Used for record
* initialization and allocation.
* @param pSrcPos The source position.
*/
DECLINLINE(PRTLOCKVALRECUNION)
rtLockValidatorRecSharedAllocOwner(PRTLOCKVALRECSHRD pRec, PRTTHREADINT pThreadSelf, PCRTLOCKVALSRCPOS pSrcPos)
{
PRTLOCKVALRECUNION pEntry;
/*
* Check if the thread has any statically allocated records we can easily
* make use of.
*/
unsigned iEntry = ASMBitFirstSetU32(ASMAtomicUoReadU32(&pThreadSelf->LockValidator.bmFreeShrdOwners));
if ( iEntry > 0
&& ASMAtomicBitTestAndClear(&pThreadSelf->LockValidator.bmFreeShrdOwners, iEntry - 1))
{
pEntry = (PRTLOCKVALRECUNION)&pThreadSelf->LockValidator.aShrdOwners[iEntry - 1];
Assert(!pEntry->ShrdOwner.fReserved);
pEntry->ShrdOwner.fStaticAlloc = true;
rtThreadGet(pThreadSelf);
}
else
{
pEntry = (PRTLOCKVALRECUNION)RTMemAlloc(sizeof(RTLOCKVALRECSHRDOWN));
if (RT_UNLIKELY(!pEntry))
return NULL;
pEntry->ShrdOwner.fStaticAlloc = false;
}
pEntry->Core.u32Magic = RTLOCKVALRECSHRDOWN_MAGIC;
pEntry->ShrdOwner.cRecursion = 1;
pEntry->ShrdOwner.fReserved = true;
pEntry->ShrdOwner.hThread = pThreadSelf;
pEntry->ShrdOwner.pDown = NULL;
pEntry->ShrdOwner.pSharedRec = pRec;
#if HC_ARCH_BITS == 32
pEntry->ShrdOwner.pvReserved = NULL;
#endif
if (pSrcPos)
pEntry->ShrdOwner.SrcPos = *pSrcPos;
else
rtLockValidatorSrcPosInit(&pEntry->ShrdOwner.SrcPos);
return pEntry;
}
/**
* Frees an owner entry allocated by rtLockValidatorRecSharedAllocOwner.
*
* @param pEntry The owner entry.
*/
DECLINLINE(void) rtLockValidatorRecSharedFreeOwner(PRTLOCKVALRECSHRDOWN pEntry)
{
if (pEntry)
{
Assert(pEntry->Core.u32Magic == RTLOCKVALRECSHRDOWN_MAGIC);
ASMAtomicWriteU32(&pEntry->Core.u32Magic, RTLOCKVALRECSHRDOWN_MAGIC_DEAD);
PRTTHREADINT pThread;
ASMAtomicXchgHandle(&pEntry->hThread, NIL_RTTHREAD, &pThread);
Assert(pEntry->fReserved);
pEntry->fReserved = false;
if (pEntry->fStaticAlloc)
{
AssertPtrReturnVoid(pThread);
AssertReturnVoid(pThread->u32Magic == RTTHREADINT_MAGIC);
uintptr_t iEntry = pEntry - &pThread->LockValidator.aShrdOwners[0];
AssertReleaseReturnVoid(iEntry < RT_ELEMENTS(pThread->LockValidator.aShrdOwners));
Assert(!ASMBitTest(&pThread->LockValidator.bmFreeShrdOwners, (int32_t)iEntry));
ASMAtomicBitSet(&pThread->LockValidator.bmFreeShrdOwners, (int32_t)iEntry);
rtThreadRelease(pThread);
}
else
{
rtLockValidatorSerializeDestructEnter();
rtLockValidatorSerializeDestructLeave();
RTMemFree(pEntry);
}
}
}
/**
* Make more room in the table.
*
* @retval true on success
* @retval false if we're out of memory or running into a bad race condition
* (probably a bug somewhere). No longer holding the lock.
*
* @param pShared The shared lock record.
*/
static bool rtLockValidatorRecSharedMakeRoom(PRTLOCKVALRECSHRD pShared)
{
for (unsigned i = 0; i < 1000; i++)
{
/*
* Switch to the other data access direction.
*/
rtLockValidatorSerializeDetectionLeave();
if (i >= 10)
{
Assert(i != 10 && i != 100);
RTThreadSleep(i >= 100);
}
rtLockValidatorSerializeDestructEnter();
/*
* Try grab the privilege to reallocating the table.
*/
if ( pShared->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC
&& ASMAtomicCmpXchgBool(&pShared->fReallocating, true, false))
{
uint32_t cAllocated = pShared->cAllocated;
if (cAllocated < pShared->cEntries)
{
/*
* Ok, still not enough space. Reallocate the table.
*/
#if 0 /** @todo enable this after making sure growing works flawlessly. */
uint32_t cInc = RT_ALIGN_32(pShared->cEntries - cAllocated, 16);
#else
uint32_t cInc = RT_ALIGN_32(pShared->cEntries - cAllocated, 1);
#endif
PRTLOCKVALRECSHRDOWN *papOwners;
papOwners = (PRTLOCKVALRECSHRDOWN *)RTMemRealloc((void *)pShared->papOwners,
(cAllocated + cInc) * sizeof(void *));
if (!papOwners)
{
ASMAtomicWriteBool(&pShared->fReallocating, false);
rtLockValidatorSerializeDestructLeave();
/* RTMemRealloc will assert */
return false;
}
while (cInc-- > 0)
{
papOwners[cAllocated] = NULL;
cAllocated++;
}
ASMAtomicWritePtr(&pShared->papOwners, papOwners);
ASMAtomicWriteU32(&pShared->cAllocated, cAllocated);
}
ASMAtomicWriteBool(&pShared->fReallocating, false);
}
rtLockValidatorSerializeDestructLeave();
rtLockValidatorSerializeDetectionEnter();
if (RT_UNLIKELY(pShared->Core.u32Magic != RTLOCKVALRECSHRD_MAGIC))
break;
if (pShared->cAllocated >= pShared->cEntries)
return true;
}
rtLockValidatorSerializeDetectionLeave();
AssertFailed(); /* too many iterations or destroyed while racing. */
return false;
}
/**
* Adds an owner entry to a shared lock record.
*
* @returns true on success, false on serious race or we're if out of memory.
* @param pShared The shared lock record.
* @param pEntry The owner entry.
*/
DECLINLINE(bool) rtLockValidatorRecSharedAddOwner(PRTLOCKVALRECSHRD pShared, PRTLOCKVALRECSHRDOWN pEntry)
{
rtLockValidatorSerializeDetectionEnter();
if (RT_LIKELY(pShared->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC)) /* paranoia */
{
if ( ASMAtomicIncU32(&pShared->cEntries) > pShared->cAllocated /** @todo add fudge */
&& !rtLockValidatorRecSharedMakeRoom(pShared))
return false; /* the worker leave the lock */
PRTLOCKVALRECSHRDOWN volatile *papOwners = pShared->papOwners;
uint32_t const cMax = pShared->cAllocated;
for (unsigned i = 0; i < 100; i++)
{
for (uint32_t iEntry = 0; iEntry < cMax; iEntry++)
{
if (ASMAtomicCmpXchgPtr(&papOwners[iEntry], pEntry, NULL))
{
rtLockValidatorSerializeDetectionLeave();
return true;
}
}
Assert(i != 25);
}
AssertFailed();
}
rtLockValidatorSerializeDetectionLeave();
return false;
}
/**
* Remove an owner entry from a shared lock record and free it.
*
* @param pShared The shared lock record.
* @param pEntry The owner entry to remove.
* @param iEntry The last known index.
*/
DECLINLINE(void) rtLockValidatorRecSharedRemoveAndFreeOwner(PRTLOCKVALRECSHRD pShared, PRTLOCKVALRECSHRDOWN pEntry,
uint32_t iEntry)
{
/*
* Remove it from the table.
*/
rtLockValidatorSerializeDetectionEnter();
AssertReturnVoidStmt(pShared->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC, rtLockValidatorSerializeDetectionLeave());
if (RT_UNLIKELY( iEntry >= pShared->cAllocated
|| !ASMAtomicCmpXchgPtr(&pShared->papOwners[iEntry], NULL, pEntry)))
{
/* this shouldn't happen yet... */
AssertFailed();
PRTLOCKVALRECSHRDOWN volatile *papOwners = pShared->papOwners;
uint32_t const cMax = pShared->cAllocated;
for (iEntry = 0; iEntry < cMax; iEntry++)
if (ASMAtomicCmpXchgPtr(&papOwners[iEntry], NULL, pEntry))
break;
AssertReturnVoidStmt(iEntry < cMax, rtLockValidatorSerializeDetectionLeave());
}
uint32_t cNow = ASMAtomicDecU32(&pShared->cEntries);
Assert(!(cNow & RT_BIT_32(31))); NOREF(cNow);
rtLockValidatorSerializeDetectionLeave();
/*
* Successfully removed, now free it.
*/
rtLockValidatorRecSharedFreeOwner(pEntry);
}
RTDECL(void) RTLockValidatorRecSharedResetOwner(PRTLOCKVALRECSHRD pRec, RTTHREAD hThread, PCRTLOCKVALSRCPOS pSrcPos)
{
AssertReturnVoid(pRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC);
if (!pRec->fEnabled)
return;
AssertReturnVoid(hThread == NIL_RTTHREAD || hThread->u32Magic == RTTHREADINT_MAGIC);
AssertReturnVoid(pRec->fSignaller);
/*
* Free all current owners.
*/
rtLockValidatorSerializeDetectionEnter();
while (ASMAtomicUoReadU32(&pRec->cEntries) > 0)
{
AssertReturnVoidStmt(pRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC, rtLockValidatorSerializeDetectionLeave());
uint32_t iEntry = 0;
uint32_t cEntries = pRec->cAllocated;
PRTLOCKVALRECSHRDOWN volatile *papEntries = pRec->papOwners;
while (iEntry < cEntries)
{
PRTLOCKVALRECSHRDOWN pEntry = ASMAtomicXchgPtrT(&papEntries[iEntry], NULL, PRTLOCKVALRECSHRDOWN);
if (pEntry)
{
ASMAtomicDecU32(&pRec->cEntries);
rtLockValidatorSerializeDetectionLeave();
rtLockValidatorRecSharedFreeOwner(pEntry);
rtLockValidatorSerializeDetectionEnter();
if (ASMAtomicUoReadU32(&pRec->cEntries) == 0)
break;
cEntries = pRec->cAllocated;
papEntries = pRec->papOwners;
}
iEntry++;
}
}
rtLockValidatorSerializeDetectionLeave();
if (hThread != NIL_RTTHREAD)
{
/*
* Allocate a new owner entry and insert it into the table.
*/
PRTLOCKVALRECUNION pEntry = rtLockValidatorRecSharedAllocOwner(pRec, hThread, pSrcPos);
if ( pEntry
&& !rtLockValidatorRecSharedAddOwner(pRec, &pEntry->ShrdOwner))
rtLockValidatorRecSharedFreeOwner(&pEntry->ShrdOwner);
}
}
RT_EXPORT_SYMBOL(RTLockValidatorRecSharedResetOwner);
RTDECL(void) RTLockValidatorRecSharedAddOwner(PRTLOCKVALRECSHRD pRec, RTTHREAD hThread, PCRTLOCKVALSRCPOS pSrcPos)
{
AssertReturnVoid(pRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC);
if (!pRec->fEnabled)
return;
if (hThread == NIL_RTTHREAD)
{
hThread = RTThreadSelfAutoAdopt();
AssertReturnVoid(hThread != NIL_RTTHREAD);
}
AssertReturnVoid(hThread->u32Magic == RTTHREADINT_MAGIC);
/*
* Recursive?
*
* Note! This code can be optimized to try avoid scanning the table on
* insert. However, that's annoying work that makes the code big,
* so it can wait til later sometime.
*/
PRTLOCKVALRECUNION pEntry = rtLockValidatorRecSharedFindOwner(pRec, hThread, NULL);
if (pEntry)
{
Assert(!pRec->fSignaller);
pEntry->ShrdOwner.cRecursion++;
rtLockValidatorStackPushRecursion(hThread, pEntry, pSrcPos);
return;
}
/*
* Allocate a new owner entry and insert it into the table.
*/
pEntry = rtLockValidatorRecSharedAllocOwner(pRec, hThread, pSrcPos);
if (pEntry)
{
if (rtLockValidatorRecSharedAddOwner(pRec, &pEntry->ShrdOwner))
{
if (!pRec->fSignaller)
rtLockValidatorStackPush(hThread, pEntry);
}
else
rtLockValidatorRecSharedFreeOwner(&pEntry->ShrdOwner);
}
}
RT_EXPORT_SYMBOL(RTLockValidatorRecSharedAddOwner);
RTDECL(void) RTLockValidatorRecSharedRemoveOwner(PRTLOCKVALRECSHRD pRec, RTTHREAD hThread)
{
AssertReturnVoid(pRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC);
if (!pRec->fEnabled)
return;
if (hThread == NIL_RTTHREAD)
{
hThread = RTThreadSelfAutoAdopt();
AssertReturnVoid(hThread != NIL_RTTHREAD);
}
AssertReturnVoid(hThread->u32Magic == RTTHREADINT_MAGIC);
/*
* Find the entry hope it's a recursive one.
*/
uint32_t iEntry = UINT32_MAX; /* shuts up gcc */
PRTLOCKVALRECUNION pEntry = rtLockValidatorRecSharedFindOwner(pRec, hThread, &iEntry);
AssertReturnVoid(pEntry);
AssertReturnVoid(pEntry->ShrdOwner.cRecursion > 0);
uint32_t c = --pEntry->ShrdOwner.cRecursion;
if (c == 0)
{
if (!pRec->fSignaller)
rtLockValidatorStackPop(hThread, (PRTLOCKVALRECUNION)pEntry);
rtLockValidatorRecSharedRemoveAndFreeOwner(pRec, &pEntry->ShrdOwner, iEntry);
}
else
{
Assert(!pRec->fSignaller);
rtLockValidatorStackPopRecursion(hThread, pEntry);
}
}
RT_EXPORT_SYMBOL(RTLockValidatorRecSharedRemoveOwner);
RTDECL(bool) RTLockValidatorRecSharedIsOwner(PRTLOCKVALRECSHRD pRec, RTTHREAD hThread)
{
/* Validate and resolve input. */
AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC, false);
if (!pRec->fEnabled)
return false;
if (hThread == NIL_RTTHREAD)
{
hThread = RTThreadSelfAutoAdopt();
AssertReturn(hThread != NIL_RTTHREAD, false);
}
AssertReturn(hThread->u32Magic == RTTHREADINT_MAGIC, false);
/* Do the job. */
PRTLOCKVALRECUNION pEntry = rtLockValidatorRecSharedFindOwner(pRec, hThread, NULL);
return pEntry != NULL;
}
RT_EXPORT_SYMBOL(RTLockValidatorRecSharedIsOwner);
RTDECL(int) RTLockValidatorRecSharedCheckAndRelease(PRTLOCKVALRECSHRD pRec, RTTHREAD hThreadSelf)
{
AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
if (!pRec->fEnabled)
return VINF_SUCCESS;
if (hThreadSelf == NIL_RTTHREAD)
{
hThreadSelf = RTThreadSelfAutoAdopt();
AssertReturn(hThreadSelf != NIL_RTTHREAD, VERR_SEM_LV_INTERNAL_ERROR);
}
Assert(hThreadSelf == RTThreadSelf());
AssertReturn(hThreadSelf->u32Magic == RTTHREADINT_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
/*
* Locate the entry for this thread in the table.
*/
uint32_t iEntry = 0;
PRTLOCKVALRECUNION pEntry = rtLockValidatorRecSharedFindOwner(pRec, hThreadSelf, &iEntry);
if (RT_UNLIKELY(!pEntry))
{
rtLockValComplainFirst("Not owner (shared)!", NULL, hThreadSelf, (PRTLOCKVALRECUNION)pRec, true);
rtLockValComplainPanic();
return VERR_SEM_LV_NOT_OWNER;
}
/*
* Check the release order.
*/
if ( pRec->hClass != NIL_RTLOCKVALCLASS
&& pRec->hClass->fStrictReleaseOrder
&& pRec->hClass->cMsMinOrder != RT_INDEFINITE_WAIT
)
{
int rc = rtLockValidatorStackCheckReleaseOrder(hThreadSelf, (PRTLOCKVALRECUNION)pEntry);
if (RT_FAILURE(rc))
return rc;
}
/*
* Release the ownership or unwind a level of recursion.
*/
Assert(pEntry->ShrdOwner.cRecursion > 0);
uint32_t c = --pEntry->ShrdOwner.cRecursion;
if (c == 0)
{
rtLockValidatorStackPop(hThreadSelf, pEntry);
rtLockValidatorRecSharedRemoveAndFreeOwner(pRec, &pEntry->ShrdOwner, iEntry);
}
else
rtLockValidatorStackPopRecursion(hThreadSelf, pEntry);
return VINF_SUCCESS;
}
RTDECL(int) RTLockValidatorRecSharedCheckSignaller(PRTLOCKVALRECSHRD pRec, RTTHREAD hThreadSelf)
{
AssertReturn(pRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
if (!pRec->fEnabled)
return VINF_SUCCESS;
if (hThreadSelf == NIL_RTTHREAD)
{
hThreadSelf = RTThreadSelfAutoAdopt();
AssertReturn(hThreadSelf != NIL_RTTHREAD, VERR_SEM_LV_INTERNAL_ERROR);
}
Assert(hThreadSelf == RTThreadSelf());
AssertReturn(hThreadSelf->u32Magic == RTTHREADINT_MAGIC, VERR_SEM_LV_INVALID_PARAMETER);
/*
* Locate the entry for this thread in the table.
*/
uint32_t iEntry = 0;
PRTLOCKVALRECUNION pEntry = rtLockValidatorRecSharedFindOwner(pRec, hThreadSelf, &iEntry);
if (RT_UNLIKELY(!pEntry))
{
rtLockValComplainFirst("Invalid signaller!", NULL, hThreadSelf, (PRTLOCKVALRECUNION)pRec, true);
rtLockValComplainPanic();
return VERR_SEM_LV_NOT_SIGNALLER;
}
return VINF_SUCCESS;
}
RTDECL(int32_t) RTLockValidatorWriteLockGetCount(RTTHREAD Thread)
{
if (Thread == NIL_RTTHREAD)
return 0;
PRTTHREADINT pThread = rtThreadGet(Thread);
if (!pThread)
return VERR_INVALID_HANDLE;
int32_t cWriteLocks = ASMAtomicReadS32(&pThread->LockValidator.cWriteLocks);
rtThreadRelease(pThread);
return cWriteLocks;
}
RT_EXPORT_SYMBOL(RTLockValidatorWriteLockGetCount);
RTDECL(void) RTLockValidatorWriteLockInc(RTTHREAD Thread)
{
PRTTHREADINT pThread = rtThreadGet(Thread);
AssertReturnVoid(pThread);
ASMAtomicIncS32(&pThread->LockValidator.cWriteLocks);
rtThreadRelease(pThread);
}
RT_EXPORT_SYMBOL(RTLockValidatorWriteLockInc);
RTDECL(void) RTLockValidatorWriteLockDec(RTTHREAD Thread)
{
PRTTHREADINT pThread = rtThreadGet(Thread);
AssertReturnVoid(pThread);
ASMAtomicDecS32(&pThread->LockValidator.cWriteLocks);
rtThreadRelease(pThread);
}
RT_EXPORT_SYMBOL(RTLockValidatorWriteLockDec);
RTDECL(int32_t) RTLockValidatorReadLockGetCount(RTTHREAD Thread)
{
if (Thread == NIL_RTTHREAD)
return 0;
PRTTHREADINT pThread = rtThreadGet(Thread);
if (!pThread)
return VERR_INVALID_HANDLE;
int32_t cReadLocks = ASMAtomicReadS32(&pThread->LockValidator.cReadLocks);
rtThreadRelease(pThread);
return cReadLocks;
}
RT_EXPORT_SYMBOL(RTLockValidatorReadLockGetCount);
RTDECL(void) RTLockValidatorReadLockInc(RTTHREAD Thread)
{
PRTTHREADINT pThread = rtThreadGet(Thread);
Assert(pThread);
ASMAtomicIncS32(&pThread->LockValidator.cReadLocks);
rtThreadRelease(pThread);
}
RT_EXPORT_SYMBOL(RTLockValidatorReadLockInc);
RTDECL(void) RTLockValidatorReadLockDec(RTTHREAD Thread)
{
PRTTHREADINT pThread = rtThreadGet(Thread);
Assert(pThread);
ASMAtomicDecS32(&pThread->LockValidator.cReadLocks);
rtThreadRelease(pThread);
}
RT_EXPORT_SYMBOL(RTLockValidatorReadLockDec);
RTDECL(void *) RTLockValidatorQueryBlocking(RTTHREAD hThread)
{
void *pvLock = NULL;
PRTTHREADINT pThread = rtThreadGet(hThread);
if (pThread)
{
RTTHREADSTATE enmState = rtThreadGetState(pThread);
if (RTTHREAD_IS_SLEEPING(enmState))
{
rtLockValidatorSerializeDetectionEnter();
enmState = rtThreadGetState(pThread);
if (RTTHREAD_IS_SLEEPING(enmState))
{
PRTLOCKVALRECUNION pRec = rtLockValidatorReadRecUnionPtr(&pThread->LockValidator.pRec);
if (pRec)
{
switch (pRec->Core.u32Magic)
{
case RTLOCKVALRECEXCL_MAGIC:
pvLock = pRec->Excl.hLock;
break;
case RTLOCKVALRECSHRDOWN_MAGIC:
pRec = (PRTLOCKVALRECUNION)pRec->ShrdOwner.pSharedRec;
if (!pRec || pRec->Core.u32Magic != RTLOCKVALRECSHRD_MAGIC)
break;
case RTLOCKVALRECSHRD_MAGIC:
pvLock = pRec->Shared.hLock;
break;
}
if (RTThreadGetState(pThread) != enmState)
pvLock = NULL;
}
}
rtLockValidatorSerializeDetectionLeave();
}
rtThreadRelease(pThread);
}
return pvLock;
}
RT_EXPORT_SYMBOL(RTLockValidatorQueryBlocking);
RTDECL(bool) RTLockValidatorIsBlockedThreadInValidator(RTTHREAD hThread)
{
bool fRet = false;
PRTTHREADINT pThread = rtThreadGet(hThread);
if (pThread)
{
fRet = ASMAtomicReadBool(&pThread->LockValidator.fInValidator);
rtThreadRelease(pThread);
}
return fRet;
}
RT_EXPORT_SYMBOL(RTLockValidatorIsBlockedThreadInValidator);
RTDECL(bool) RTLockValidatorHoldsLocksInClass(RTTHREAD hCurrentThread, RTLOCKVALCLASS hClass)
{
bool fRet = false;
if (hCurrentThread == NIL_RTTHREAD)
hCurrentThread = RTThreadSelf();
else
Assert(hCurrentThread == RTThreadSelf());
PRTTHREADINT pThread = rtThreadGet(hCurrentThread);
if (pThread)
{
if (hClass != NIL_RTLOCKVALCLASS)
{
PRTLOCKVALRECUNION pCur = rtLockValidatorReadRecUnionPtr(&pThread->LockValidator.pStackTop);
while (VALID_PTR(pCur) && !fRet)
{
switch (pCur->Core.u32Magic)
{
case RTLOCKVALRECEXCL_MAGIC:
fRet = pCur->Excl.hClass == hClass;
pCur = rtLockValidatorReadRecUnionPtr(&pCur->Excl.pDown);
break;
case RTLOCKVALRECSHRDOWN_MAGIC:
fRet = VALID_PTR(pCur->ShrdOwner.pSharedRec)
&& pCur->ShrdOwner.pSharedRec->hClass == hClass;
pCur = rtLockValidatorReadRecUnionPtr(&pCur->ShrdOwner.pDown);
break;
case RTLOCKVALRECNEST_MAGIC:
switch (pCur->Nest.pRec->Core.u32Magic)
{
case RTLOCKVALRECEXCL_MAGIC:
fRet = pCur->Nest.pRec->Excl.hClass == hClass;
break;
case RTLOCKVALRECSHRDOWN_MAGIC:
fRet = VALID_PTR(pCur->ShrdOwner.pSharedRec)
&& pCur->Nest.pRec->ShrdOwner.pSharedRec->hClass == hClass;
break;
}
pCur = rtLockValidatorReadRecUnionPtr(&pCur->Nest.pDown);
break;
default:
pCur = NULL;
break;
}
}
}
rtThreadRelease(pThread);
}
return fRet;
}
RT_EXPORT_SYMBOL(RTLockValidatorHoldsLocksInClass);
RTDECL(bool) RTLockValidatorHoldsLocksInSubClass(RTTHREAD hCurrentThread, RTLOCKVALCLASS hClass, uint32_t uSubClass)
{
bool fRet = false;
if (hCurrentThread == NIL_RTTHREAD)
hCurrentThread = RTThreadSelf();
else
Assert(hCurrentThread == RTThreadSelf());
PRTTHREADINT pThread = rtThreadGet(hCurrentThread);
if (pThread)
{
if (hClass != NIL_RTLOCKVALCLASS)
{
PRTLOCKVALRECUNION pCur = rtLockValidatorReadRecUnionPtr(&pThread->LockValidator.pStackTop);
while (VALID_PTR(pCur) && !fRet)
{
switch (pCur->Core.u32Magic)
{
case RTLOCKVALRECEXCL_MAGIC:
fRet = pCur->Excl.hClass == hClass
&& pCur->Excl.uSubClass == uSubClass;
pCur = rtLockValidatorReadRecUnionPtr(&pCur->Excl.pDown);
break;
case RTLOCKVALRECSHRDOWN_MAGIC:
fRet = VALID_PTR(pCur->ShrdOwner.pSharedRec)
&& pCur->ShrdOwner.pSharedRec->hClass == hClass
&& pCur->ShrdOwner.pSharedRec->uSubClass == uSubClass;
pCur = rtLockValidatorReadRecUnionPtr(&pCur->ShrdOwner.pDown);
break;
case RTLOCKVALRECNEST_MAGIC:
switch (pCur->Nest.pRec->Core.u32Magic)
{
case RTLOCKVALRECEXCL_MAGIC:
fRet = pCur->Nest.pRec->Excl.hClass == hClass
&& pCur->Nest.pRec->Excl.uSubClass == uSubClass;
break;
case RTLOCKVALRECSHRDOWN_MAGIC:
fRet = VALID_PTR(pCur->ShrdOwner.pSharedRec)
&& pCur->Nest.pRec->ShrdOwner.pSharedRec->hClass == hClass
&& pCur->Nest.pRec->ShrdOwner.pSharedRec->uSubClass == uSubClass;
break;
}
pCur = rtLockValidatorReadRecUnionPtr(&pCur->Nest.pDown);
break;
default:
pCur = NULL;
break;
}
}
}
rtThreadRelease(pThread);
}
return fRet;
}
RT_EXPORT_SYMBOL(RTLockValidatorHoldsLocksInClass);
RTDECL(bool) RTLockValidatorSetEnabled(bool fEnabled)
{
return ASMAtomicXchgBool(&g_fLockValidatorEnabled, fEnabled);
}
RT_EXPORT_SYMBOL(RTLockValidatorSetEnabled);
RTDECL(bool) RTLockValidatorIsEnabled(void)
{
return ASMAtomicUoReadBool(&g_fLockValidatorEnabled);
}
RT_EXPORT_SYMBOL(RTLockValidatorIsEnabled);
RTDECL(bool) RTLockValidatorSetQuiet(bool fQuiet)
{
return ASMAtomicXchgBool(&g_fLockValidatorQuiet, fQuiet);
}
RT_EXPORT_SYMBOL(RTLockValidatorSetQuiet);
RTDECL(bool) RTLockValidatorIsQuiet(void)
{
return ASMAtomicUoReadBool(&g_fLockValidatorQuiet);
}
RT_EXPORT_SYMBOL(RTLockValidatorIsQuiet);
RTDECL(bool) RTLockValidatorSetMayPanic(bool fMayPanic)
{
return ASMAtomicXchgBool(&g_fLockValidatorMayPanic, fMayPanic);
}
RT_EXPORT_SYMBOL(RTLockValidatorSetMayPanic);
RTDECL(bool) RTLockValidatorMayPanic(void)
{
return ASMAtomicUoReadBool(&g_fLockValidatorMayPanic);
}
RT_EXPORT_SYMBOL(RTLockValidatorMayPanic);