lockvalidator.cpp revision 645c172620d19e7aceca8b5ba9a904619681099d
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * IPRT - Lock Validator.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Copyright (C) 2009-2012 Oracle Corporation
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 * 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.
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.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/*******************************************************************************
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync* Header Files *
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 AssertMsg(!((uintptr_t)(p) & (sizeof(uintptr_t) - 1)), ("%p\n", (p)));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync# define RTLOCKVAL_ASSERT_PTR_ALIGN(p) do { } while (0)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** Hashes the class handle (pointer) into an apPriorLocksHash index. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync % ( RT_SIZEOFMEMB(RTLOCKVALCLASSINT, apPriorLocksHash) \
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)
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync/** @def RTLOCKVAL_WITH_RECURSION_RECORDS
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Enable recursion records. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** @def RTLOCKVAL_WITH_VERBOSE_DUMPS
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Enables some extra verbosity in the lock dumping. */
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync/** @def RTLOCKVAL_WITH_CLASS_HASH_STATS
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync * Enables collection prior class hash lookup statistics, dumping them when
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync * complaining about the class. */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync/*******************************************************************************
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync* Structures and Typedefs *
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync*******************************************************************************/
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync * Deadlock detection stack entry.
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync /** The current record. */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync /** The current entry number if pRec is a shared one. */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync /** The thread state of the thread we followed to get to pFirstSibling.
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync * This is only used for validating a deadlock stack. */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync /** The thread we followed to get to pFirstSibling.
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync * This is only used for validating a deadlock stack. */
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 * Deadlock detection stack.
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync /** The number stack entries. */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync /** The stack entries. */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync/** Pointer to a deadlock detection stack. */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync * Reference to another class.
56602ba12f2388501d594c83fbbf77b4b16f8f4fvboxsync /** The class. */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync /** The number of lookups of this class. */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync /** Indicates whether the entry was added automatically during order checking
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync * (true) or manually via the API (false). */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync /** Reserved / explicit alignment padding. */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync/** Pointer to a class reference. */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync/** Pointer to a chunk of class references. */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsynctypedef struct RTLOCKVALCLASSREFCHUNK *PRTLOCKVALCLASSREFCHUNK;
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync * Chunk of class references.
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync /** Array of refs. */
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync#if 0 /** @todo for testing allocation of new chunks. */
51e7ffc68ae0a6122fcfdc746905b6c7dae2c610vboxsync /** Pointer to the next chunk. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Lock class.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** AVL node core. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** Magic value (RTLOCKVALCLASS_MAGIC). */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** Reference counter. See RTLOCKVALCLASS_MAX_REFS. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** Whether the class is allowed to teach it self new locking order rules. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** Whether to allow recursion. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** Strict release order. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** Whether this class is in the tree. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** Donate a reference to the next retainer. This is a hack to make
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * RTLockValidatorClassCreateUnique work. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** Reserved future use / explicit alignment. */
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync /** The minimum wait interval for which we do deadlock detection
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync * (milliseconds). */
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync /** The minimum wait interval for which we do order checks (milliseconds). */
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync /** More padding. */
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. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** Hash table containing frequently encountered prior locks. */
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 /** Hash hits. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** Hash misses. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncAssertCompileSize(AVLLU32NODECORE, ARCH_BITS == 32 ? 20 : 32);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncAssertCompileMemberOffset(RTLOCKVALCLASSINT, PriorLocks, 64);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/*******************************************************************************
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync* Global Variables *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync*******************************************************************************/
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** Serializing object destruction and deadlock detection.
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 * NS: RTLOCKVALREC*, RTTHREADINT and RTLOCKVALDRECSHRD::papOwners destruction.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * EW: Deadlock detection and some related activities.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic RTSEMXROADS g_hLockValidatorXRoads = NIL_RTSEMXROADS;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** Serializing class tree insert and lookups. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic RTSEMRW g_hLockValClassTreeRWLock= NIL_RTSEMRW;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** Class tree. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** Critical section serializing the teaching new rules to the classes. */
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. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic bool volatile g_fLockValidatorQuiet = false;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic bool volatile g_fLockValidatorQuiet = true;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** Set if the lock validator may panic. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic bool volatile g_fLockValidatorMayPanic = true;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic bool volatile g_fLockValidatorMayPanic = false;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** Whether to return an error status on wrong locking order. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic bool volatile g_fLockValSoftWrongOrder = false;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/*******************************************************************************
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync* Internal Functions *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync*******************************************************************************/
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic void rtLockValidatorClassDestroy(RTLOCKVALCLASSINT *pClass);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic uint32_t rtLockValidatorStackDepth(PRTTHREADINT pThread);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Lazy initialization of the lock validator globals.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic void rtLockValidatorLazyInit(void)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (ASMAtomicCmpXchgU32(&s_fInitializing, true, false))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * The locks.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (!RTCritSectIsInitialized(&g_LockValClassTeachCS))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTCritSectInitEx(&g_LockValClassTeachCS, RTCRITSECT_FLAGS_NO_LOCK_VAL, NIL_RTLOCKVALCLASS,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync int rc = RTSemRWCreateEx(&hSemRW, RTSEMRW_FLAGS_NO_LOCK_VAL, NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_ANY, "RTLockVal-Tree");
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteHandle(&g_hLockValClassTreeRWLock, hSemRW);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteHandle(&g_hLockValidatorXRoads, hXRoads);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Check the environment for our config variables.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteBool(&g_fLockValidatorEnabled, true);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteBool(&g_fLockValidatorEnabled, false);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteBool(&g_fLockValidatorMayPanic, true);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (RTEnvExist("IPRT_LOCK_VALIDATOR_MAY_NOT_PANIC"))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteBool(&g_fLockValidatorMayPanic, false);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (RTEnvExist("IPRT_LOCK_VALIDATOR_STRICT_ORDER"))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteBool(&g_fLockValSoftWrongOrder, false);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteBool(&g_fLockValSoftWrongOrder, true);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Register cleanup
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /** @todo register some cleanup callback if we care. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** Wrapper around ASMAtomicReadPtr. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncDECL_FORCE_INLINE(PRTLOCKVALRECUNION) rtLockValidatorReadRecUnionPtr(PRTLOCKVALRECUNION volatile *ppRec)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTLOCKVALRECUNION p = ASMAtomicReadPtrT(ppRec, PRTLOCKVALRECUNION);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** Wrapper around ASMAtomicWritePtr. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncDECL_FORCE_INLINE(void) rtLockValidatorWriteRecUnionPtr(PRTLOCKVALRECUNION volatile *ppRec, PRTLOCKVALRECUNION pRecNew)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** Wrapper around ASMAtomicReadPtr. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncDECL_FORCE_INLINE(PRTTHREADINT) rtLockValidatorReadThreadHandle(RTTHREAD volatile *phThread)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTTHREADINT p = ASMAtomicReadPtrT(phThread, PRTTHREADINT);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** Wrapper around ASMAtomicUoReadPtr. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncDECL_FORCE_INLINE(PRTLOCKVALRECSHRDOWN) rtLockValidatorUoReadSharedOwner(PRTLOCKVALRECSHRDOWN volatile *ppOwner)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTLOCKVALRECSHRDOWN p = ASMAtomicUoReadPtrT(ppOwner, PRTLOCKVALRECSHRDOWN);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Reads a volatile thread handle field and returns the thread name.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @returns Thread name (read only).
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param phThread The thread handle field.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic const char *rtLockValidatorNameThreadHandle(RTTHREAD volatile *phThread)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTTHREADINT pThread = rtLockValidatorReadThreadHandle(phThread);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return "<NIL>";
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return "<INVALID>";
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return "<BAD-THREAD-MAGIC>";
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Launch a simple assertion like complaint w/ panic.
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.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic void rtLockValComplain(RT_SRC_POS_DECL, const char *pszWhat, ...)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTAssertMsg1Weak("RTLockValidator", iLine, pszFile, pszFunction);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Describes the class.
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
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic void rtLockValComplainAboutClass(const char *pszPrefix, RTLOCKVALCLASSINT *pClass, uint32_t uSubClass, bool fVerbose)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /* Stringify the sub-class. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync case RTLOCKVAL_SUB_CLASS_NONE: pszSubClass = "none"; break;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync case RTLOCKVAL_SUB_CLASS_ANY: pszSubClass = "any"; break;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTStrPrintf(szSubClass, sizeof(szSubClass), "invl-%u", uSubClass);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTStrPrintf(szSubClass, sizeof(szSubClass), "%u", uSubClass);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /* Validate the class pointer. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTAssertMsg2AddWeak("%sbad class=%p sub-class=%s\n", pszPrefix, pClass, pszSubClass);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTAssertMsg2AddWeak("%sbad class=%p magic=%#x sub-class=%s\n", pszPrefix, pClass, pClass->u32Magic, pszSubClass);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /* OK, dump the class info. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTAssertMsg2AddWeak("%sclass=%p %s created={%Rbn(%u) %Rfn %p} sub-class=%s\n", pszPrefix,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync for (PRTLOCKVALCLASSREFCHUNK pChunk = &pClass->PriorLocks; pChunk; pChunk = pChunk->pNext)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync for (unsigned j = 0; j < RT_ELEMENTS(pChunk->aRefs); j++, i++)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTLOCKVALCLASSINT *pCurClass = pChunk->aRefs[j].hClass;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTAssertMsg2AddWeak("%s%s #%02u: %s, %s, %u lookup%s\n", pszPrefix,
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync ? "autodidactic"
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync : "manually ",
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync RTAssertMsg2AddWeak("%sHash Stats: %u hits, %u misses\n", pszPrefix, pClass->cHashHits, pClass->cHashMisses);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync for (PRTLOCKVALCLASSREFCHUNK pChunk = &pClass->PriorLocks; pChunk; pChunk = pChunk->pNext)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync for (unsigned j = 0; j < RT_ELEMENTS(pChunk->aRefs); j++)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTLOCKVALCLASSINT *pCurClass = pChunk->aRefs[j].hClass;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTAssertMsg2AddWeak("%sPrior classes: %s%s", pszPrefix, pCurClass->pszName,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTAssertMsg2AddWeak(", %s%s\n", pCurClass->pszName,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTAssertMsg2AddWeak("%sPrior classes: none\n", pszPrefix);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Helper for getting the class name.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @returns Class name string.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pClass The class.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic const char *rtLockValComplainGetClassName(RTLOCKVALCLASSINT *pClass)
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync return "<nil-class>";
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync return "<bad-class-ptr>";
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync return "<bad-class-magic>";
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync return "<no-class-name>";
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync * Formats the sub-class.
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync * @returns Stringified sub-class.
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync * @param uSubClass The name.
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync * @param pszBuf Buffer that is big enough.
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsyncstatic const char *rtLockValComplainGetSubClassName(uint32_t uSubClass, char *pszBuf)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Helper for rtLockValComplainAboutLock.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncDECL_FORCE_INLINE(void) rtLockValComplainAboutLockHlp(const char *pszPrefix, PRTLOCKVALRECUNION pRec, const char *pszSuffix,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync uint32_t u32Magic, PCRTLOCKVALSRCPOS pSrcPos, uint32_t cRecursion,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTAssertMsg2AddWeak("%s%p %s xrec=%p own=%s r=%u cls=%s/%s pos={%Rbn(%u) %Rfn %p} [x%s]%s", pszPrefix,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rtLockValidatorNameThreadHandle(&pRec->Excl.hThread), cRecursion,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rtLockValComplainGetSubClassName(pRec->Excl.uSubClass, szBuf),
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pSrcPos->pszFile, pSrcPos->uLine, pSrcPos->pszFunction, pSrcPos->uId,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTAssertMsg2AddWeak("%s%p %s own=%s r=%u cls=%s/%s pos={%Rbn(%u) %Rfn %p} [x%s]%s", pszPrefix,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rtLockValidatorNameThreadHandle(&pRec->Excl.hThread), cRecursion,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rtLockValComplainGetSubClassName(pRec->Excl.uSubClass, szBuf),
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pSrcPos->pszFile, pSrcPos->uLine, pSrcPos->pszFunction, pSrcPos->uId,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTAssertMsg2AddWeak("%ss %p %s srec=%p cls=%s/%s [s%s]%s", pszPrefix,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rtLockValComplainGetClassName(pRec->Shared.hClass),
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rtLockValComplainGetSubClassName(pRec->Shared.uSubClass, szBuf),
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTLOCKVALRECSHRD pShared = pRec->ShrdOwner.pSharedRec;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync && pShared->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC)
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,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pRec, rtLockValidatorNameThreadHandle(&pRec->ShrdOwner.hThread), cRecursion,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync rtLockValComplainGetSubClassName(pShared->uSubClass, szBuf),
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pSrcPos->pszFile, pSrcPos->uLine, pSrcPos->pszFunction, pSrcPos->uId,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync RTAssertMsg2AddWeak("%s%p %s own=%s r=%u cls=%s/%s pos={%Rbn(%u) %Rfn %p} [o%s]%s", pszPrefix,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync rtLockValidatorNameThreadHandle(&pRec->ShrdOwner.hThread), cRecursion,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync rtLockValComplainGetSubClassName(pShared->uSubClass, szBuf),
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pSrcPos->pszFile, pSrcPos->uLine, pSrcPos->pszFunction, pSrcPos->uId,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync RTAssertMsg2AddWeak("%sbad srec=%p trec=%p own=%s r=%u pos={%Rbn(%u) %Rfn %p} [x%s]%s", pszPrefix,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pRec, rtLockValidatorNameThreadHandle(&pRec->ShrdOwner.hThread), cRecursion,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pSrcPos->pszFile, pSrcPos->uLine, pSrcPos->pszFunction, pSrcPos->uId,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * Describes the lock.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @param pszPrefix Message prefix.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @param pRec The lock record we're working on.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @param pszSuffix Message suffix.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsyncstatic void rtLockValComplainAboutLock(const char *pszPrefix, PRTLOCKVALRECUNION pRec, const char *pszSuffix)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync# define FIX_REC(r) (r)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync rtLockValComplainAboutLockHlp(pszPrefix, pRec, pszSuffix, RTLOCKVALRECEXCL_MAGIC,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync &pRec->Excl.SrcPos, FIX_REC(pRec->Excl.cRecursion), "");
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync rtLockValComplainAboutLockHlp(pszPrefix, pRec, pszSuffix, RTLOCKVALRECSHRD_MAGIC, NULL, 0, "");
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync rtLockValComplainAboutLockHlp(pszPrefix, pRec, pszSuffix, RTLOCKVALRECSHRDOWN_MAGIC,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync &pRec->ShrdOwner.SrcPos, FIX_REC(pRec->ShrdOwner.cRecursion), "");
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync && ( (u32Magic = pRealRec->Core.u32Magic) == RTLOCKVALRECEXCL_MAGIC
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync rtLockValComplainAboutLockHlp(pszPrefix, pRealRec, pszSuffix, u32Magic,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync RTAssertMsg2AddWeak("%sbad rrec=%p nrec=%p r=%u pos={%Rbn(%u) %Rfn %p}%s", pszPrefix,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pRec->Nest.SrcPos.pszFile, pRec->Nest.SrcPos.uLine, pRec->Nest.SrcPos.pszFunction, pRec->Nest.SrcPos.uId,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync RTAssertMsg2AddWeak("%spRec=%p u32Magic=%#x (bad)%s", pszPrefix, pRec, pRec->Core.u32Magic, pszSuffix);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * Dump the lock stack.
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 * @param pHighightRec Record that should be marked specially in the
6e7c344fc7cdb580356704e8201207b394d367bbvboxsyncstatic void rtLockValComplainAboutLockStack(PRTTHREADINT pThread, unsigned cchIndent, uint32_t cMinFrames,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync uint32_t cEntries = rtLockValidatorStackDepth(pThread);
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 RTStrPrintf(szPrefix, sizeof(szPrefix), "%*s#%02u: ", cchIndent, "", i);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync rtLockValComplainAboutLock(szPrefix, pCur, pHighightRec != pCur ? "\n" : " (*)\n");
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;
841fc232dfd102207563580ef5b2875edb98e305vboxsync RTAssertMsg2AddWeak("%*s<bad stack frame>\n", cchIndent, "");
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync RTAssertMsg2AddWeak("%*s---- end of lock stack ----\n", cchIndent, "");
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * Launch the initial complaint.
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
6e7c344fc7cdb580356704e8201207b394d367bbvboxsyncstatic void rtLockValComplainFirst(const char *pszWhat, PCRTLOCKVALSRCPOS pSrcPos, PRTTHREADINT pThreadSelf,
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync RTAssertMsg1Weak("RTLockValidator", pSrcPos ? pSrcPos->uLine : 0, pSrcPos ? pSrcPos->pszFile : NULL, pSrcPos ? pSrcPos->pszFunction : NULL);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync RTAssertMsg2Weak("%s [uId=%p thrd=%s]\n", pszWhat, pSrcPos->uId, VALID_PTR(pThreadSelf) ? pThreadSelf->szName : "<NIL>");
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync RTAssertMsg2Weak("%s [thrd=%s]\n", pszWhat, VALID_PTR(pThreadSelf) ? pThreadSelf->szName : "<NIL>");
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync rtLockValComplainAboutLockStack(pThreadSelf, 0, 1, pRec);
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync * Continue bitching.
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync * @param pszFormat Format string.
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync * @param ... Format arguments.
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsyncstatic void rtLockValComplainMore(const char *pszFormat, ...)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * Raise a panic if enabled.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsyncstatic void rtLockValComplainPanic(void)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync if (ASMAtomicUoReadBool(&g_fLockValidatorMayPanic))
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * Copy a source position record.
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync * @param pDst The destination.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @param pSrc The source. Can be NULL.
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsyncDECL_FORCE_INLINE(void) rtLockValidatorSrcPosCopy(PRTLOCKVALSRCPOS pDst, PCRTLOCKVALSRCPOS pSrc)
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync ASMAtomicUoWritePtr(&pDst->pszFile, pSrc->pszFile);
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync ASMAtomicUoWritePtr(&pDst->pszFunction, pSrc->pszFunction);
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync ASMAtomicUoWritePtr((void * volatile *)&pDst->uId, (void *)pSrc->uId);
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync * Init a source position record.
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsync * @param pSrcPos The source position record.
c697d02eb4ededad7e08b2c48428ddb56c844a0avboxsyncDECL_FORCE_INLINE(void) rtLockValidatorSrcPosInit(PRTLOCKVALSRCPOS pSrcPos)
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync * Hashes the specified source position.
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync * @returns Hash.
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync * @param pSrcPos The source position record.
e42c49edebbc79edb6d87377bab6d879fdb602favboxsyncstatic uint32_t rtLockValidatorSrcPosHash(PCRTLOCKVALSRCPOS pSrcPos)
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync * Compares two source positions.
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.
e42c49edebbc79edb6d87377bab6d879fdb602favboxsyncstatic int rtLockValidatorSrcPosCompare(PCRTLOCKVALSRCPOS pSrcPos1, PCRTLOCKVALSRCPOS pSrcPos2)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync int iDiff = RTStrCmp(pSrcPos1->pszFile, pSrcPos2->pszFile);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync iDiff = RTStrCmp(pSrcPos1->pszFunction, pSrcPos2->pszFunction);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Serializes destruction of RTLOCKVALREC* and RTTHREADINT structures.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsyncDECLHIDDEN(void) rtLockValidatorSerializeDestructEnter(void)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Call after rtLockValidatorSerializeDestructEnter.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsyncDECLHIDDEN(void) rtLockValidatorSerializeDestructLeave(void)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Serializes deadlock detection against destruction of the objects being
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * inspected.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsyncDECLINLINE(void) rtLockValidatorSerializeDetectionEnter(void)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Call after rtLockValidatorSerializeDetectionEnter.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsyncDECLHIDDEN(void) rtLockValidatorSerializeDetectionLeave(void)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Initializes the per thread lock validator data.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * @param pPerThread The data.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsyncDECLHIDDEN(void) rtLockValidatorInitPerThread(RTLOCKVALPERTHREAD *pPerThread)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync /* ASSUMES the rest has already been zeroed. */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Delete the per thread lock validator data.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * @param pPerThread The data.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsyncDECLHIDDEN(void) rtLockValidatorDeletePerThread(RTLOCKVALPERTHREAD *pPerThread)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Check that the thread doesn't own any locks at this time.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValComplainFirst("Thread terminating owning locks!", NULL,
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync RT_FROM_MEMBER(pPerThread, RTTHREADINT, LockValidator),
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Free the recursion records.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync PRTLOCKVALRECNEST pCur = pPerThread->pFreeNestRecs;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsyncRTDECL(int) RTLockValidatorClassCreateEx(PRTLOCKVALCLASS phClass, PCRTLOCKVALSRCPOS pSrcPos,
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync bool fAutodidact, bool fRecursionOk, bool fStrictReleaseOrder,
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync RTMSINTERVAL cMsMinDeadlock, RTMSINTERVAL cMsMinOrder,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync const char *pszNameFmt, ...)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync int rc = RTLockValidatorClassCreateExV(phClass, pSrcPos, fAutodidact, fRecursionOk, fStrictReleaseOrder,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncRTDECL(int) RTLockValidatorClassCreateExV(PRTLOCKVALCLASS phClass, PCRTLOCKVALSRCPOS pSrcPos,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync bool fAutodidact, bool fRecursionOk, bool fStrictReleaseOrder,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTMSINTERVAL cMsMinDeadlock, RTMSINTERVAL cMsMinOrder,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Format the name and calc its length.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync cbName = RTStrPrintfV(szName, sizeof(szName), pszNameFmt, va) + 1;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync cbName = RTStrPrintf(szName, sizeof(szName), "anon-%u", i - 1) + 1;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Figure out the file and function name lengths and allocate memory for
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 * Initialize the class data.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pThis->Core.Key = rtLockValidatorSrcPosHash(pSrcPos);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync for (unsigned i = 0; i < RT_ELEMENTS(pThis->au32Reserved); i++)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync for (unsigned i = 0; i < RT_ELEMENTS(pThis->PriorLocks.aRefs); i++)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pThis->PriorLocks.aRefs[i].hClass = NIL_RTLOCKVALCLASS;
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync pThis->PriorLocks.aRefs[i].fAutodidacticism = false;
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync for (unsigned i = 0; i < RT_ELEMENTS(pThis->apPriorLocksHash); i++)
f8220bb50249140c67ecb7267e9870ee19ca159fvboxsync pThis->pszName = (char *)memcpy(pszDst, szName, cbName);
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync rtLockValidatorSrcPosCopy(&pThis->CreatePos, pSrcPos);
f8220bb50249140c67ecb7267e9870ee19ca159fvboxsync pThis->CreatePos.pszFile = pSrcPos->pszFile ? (char *)memcpy(pszDst, pSrcPos->pszFile, cbFile) : NULL;
0bebd3a2671042901f1fcceff14f8c58dd397478vboxsync pThis->CreatePos.pszFunction= pSrcPos->pszFunction ? (char *)memcpy(pszDst, pSrcPos->pszFunction, cbFunction) : NULL;
f8220bb50249140c67ecb7267e9870ee19ca159fvboxsync Assert(rtLockValidatorSrcPosHash(&pThis->CreatePos) == pThis->Core.Key);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncRTDECL(int) RTLockValidatorClassCreate(PRTLOCKVALCLASS phClass, bool fAutodidact, RT_SRC_POS_DECL, const char *pszNameFmt, ...)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_POS_NO_ID();
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync int rc = RTLockValidatorClassCreateExV(phClass, &SrcPos,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync fAutodidact, true /*fRecursionOk*/, false /*fStrictReleaseOrder*/,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Creates a new lock validator class with a reference that is consumed by the
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * first call to RTLockValidatorClassRetain.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * This is tailored for use in the parameter list of a semaphore constructor.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @returns Class handle with a reference that is automatically consumed by the
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * first retainer. NIL_RTLOCKVALCLASS if we run into trouble.
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.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncRTDECL(RTLOCKVALCLASS) RTLockValidatorClassCreateUnique(RT_SRC_POS_DECL, const char *pszNameFmt, ...)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_POS_NO_ID();
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync int rc = RTLockValidatorClassCreateExV(&pClass, &SrcPos,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync true /*fAutodidact*/, true /*fRecursionOk*/, false /*fStrictReleaseOrder*/,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteBool(&pClass->fDonateRefToNextRetainer, true); /* see rtLockValidatorClassRetain */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Internal class retainer.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @returns The new reference count.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pClass The class.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncDECL_FORCE_INLINE(uint32_t) rtLockValidatorClassRetain(RTLOCKVALCLASSINT *pClass)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteU32(&pClass->cRefs, RTLOCKVALCLASS_MAX_REFS);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync && ASMAtomicXchgBool(&pClass->fDonateRefToNextRetainer, false))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Validates and retains a lock validator class.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @returns @a hClass on success, NIL_RTLOCKVALCLASS on failure.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param hClass The class handle. NIL_RTLOCKVALCLASS is ok.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncDECL_FORCE_INLINE(RTLOCKVALCLASS) rtLockValidatorClassValidateAndRetain(RTLOCKVALCLASS hClass)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertReturn(hClass->u32Magic == RTLOCKVALCLASS_MAGIC, NIL_RTLOCKVALCLASS);
af8d59d05d72f134aeea62712f1286b369807d52vboxsync * Internal class releaser.
af8d59d05d72f134aeea62712f1286b369807d52vboxsync * @returns The new reference count.
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync * @param pClass The class.
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsyncDECLINLINE(uint32_t) rtLockValidatorClassRelease(RTLOCKVALCLASSINT *pClass)
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync ASMAtomicWriteU32(&pClass->cRefs, RTLOCKVALCLASS_MAX_REFS);
e42c49edebbc79edb6d87377bab6d879fdb602favboxsync * Destroys a class once there are not more references to it.
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync * @param Class The class.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic void rtLockValidatorClassDestroy(RTLOCKVALCLASSINT *pClass)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteU32(&pClass->u32Magic, RTLOCKVALCLASS_MAGIC_DEAD);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTLOCKVALCLASSREFCHUNK pChunk = &pClass->PriorLocks;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pChunk->aRefs); i++)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync RTLOCKVALCLASSINT *pClass2 = pChunk->aRefs[i].hClass;
061bebe04c5bfa05ed733d2a1204389c2a0c96a8vboxsyncRTDECL(RTLOCKVALCLASS) RTLockValidatorClassFindForSrcPos(PRTLOCKVALSRCPOS pSrcPos)
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync int rcLock = RTSemRWRequestRead(g_hLockValClassTreeRWLock, RT_INDEFINITE_WAIT);
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync uint32_t uSrcPosHash = rtLockValidatorSrcPosHash(pSrcPos);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync RTLOCKVALCLASSINT *pClass = (RTLOCKVALCLASSINT *)RTAvllU32Get(&g_LockValClassTree, uSrcPosHash);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync if (rtLockValidatorSrcPosCompare(&pClass->CreatePos, pSrcPos) == 0)
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsyncRTDECL(RTLOCKVALCLASS) RTLockValidatorClassForSrcPos(RT_SRC_POS_DECL, const char *pszNameFmt, ...)
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_POS_NO_ID();
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync RTLOCKVALCLASS hClass = RTLockValidatorClassFindForSrcPos(&SrcPos);
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync * Create a new class and insert it into the tree.
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync int rc = RTLockValidatorClassCreateExV(&hClass, &SrcPos,
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync true /*fAutodidact*/, true /*fRecursionOk*/, false /*fStrictReleaseOrder*/,
509a2f53cb92e3bf060f4615936354188ce92836vboxsync int rcLock = RTSemRWRequestWrite(g_hLockValClassTreeRWLock, RT_INDEFINITE_WAIT);
509a2f53cb92e3bf060f4615936354188ce92836vboxsync hClass->fInTree = RTAvllU32Insert(&g_LockValClassTree, &hClass->Core);
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsyncRTDECL(uint32_t) RTLockValidatorClassRetain(RTLOCKVALCLASS hClass)
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync AssertReturn(pClass->u32Magic == RTLOCKVALCLASS_MAGIC, UINT32_MAX);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncRTDECL(uint32_t) RTLockValidatorClassRelease(RTLOCKVALCLASS hClass)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertReturn(pClass->u32Magic == RTLOCKVALCLASS_MAGIC, UINT32_MAX);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Worker for rtLockValidatorClassIsPriorClass that does a linear search thru
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * all the chunks for @a pPriorClass.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @returns true / false.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pClass The class to search.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pPriorClass The class to search for.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic bool rtLockValidatorClassIsPriorClassByLinearSearch(RTLOCKVALCLASSINT *pClass, RTLOCKVALCLASSINT *pPriorClass)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync for (PRTLOCKVALCLASSREFCHUNK pChunk = &pClass->PriorLocks; pChunk; pChunk = pChunk->pNext)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pChunk->aRefs); i++)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync uint32_t cLookups = ASMAtomicIncU32(&pChunk->aRefs[i].cLookups);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (RT_UNLIKELY(cLookups >= RTLOCKVALCLASSREF_MAX_LOOKUPS_FIX))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteU32(&pChunk->aRefs[i].cLookups, RTLOCKVALCLASSREF_MAX_LOOKUPS);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /* update the hash table entry. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTLOCKVALCLASSREF *ppHashEntry = &pClass->apPriorLocksHash[RTLOCKVALCLASS_HASH(pPriorClass)];
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return true;
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync return false;
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync * Checks if @a pPriorClass is a known prior class.
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync * @returns true / false.
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync * @param pClass The class to search.
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync * @param pPriorClass The class to search for.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncDECL_FORCE_INLINE(bool) rtLockValidatorClassIsPriorClass(RTLOCKVALCLASSINT *pClass, RTLOCKVALCLASSINT *pPriorClass)
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync * Hash lookup here.
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync PRTLOCKVALCLASSREF pRef = pClass->apPriorLocksHash[RTLOCKVALCLASS_HASH(pPriorClass)];
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync uint32_t cLookups = ASMAtomicIncU32(&pRef->cLookups);
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync if (RT_UNLIKELY(cLookups >= RTLOCKVALCLASSREF_MAX_LOOKUPS_FIX))
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync ASMAtomicWriteU32(&pRef->cLookups, RTLOCKVALCLASSREF_MAX_LOOKUPS);
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync return true;
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync return rtLockValidatorClassIsPriorClassByLinearSearch(pClass, pPriorClass);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Adds a class to the prior list.
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).
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsyncstatic int rtLockValidatorClassAddPriorClass(RTLOCKVALCLASSINT *pClass, RTLOCKVALCLASSINT *pPriorClass,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (!RTCritSectIsInitialized(&g_LockValClassTeachCS))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync int rcLock = RTCritSectEnter(&g_LockValClassTeachCS);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Check that there are no conflict (no assert since we might race each other).
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (!rtLockValidatorClassIsPriorClass(pPriorClass, pClass))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (!rtLockValidatorClassIsPriorClass(pClass, pPriorClass))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Scan the table for a free entry, allocating a new chunk if necessary.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync for (PRTLOCKVALCLASSREFCHUNK pChunk = &pClass->PriorLocks; ; pChunk = pChunk->pNext)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync bool fDone = false;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pChunk->aRefs); i++)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicCmpXchgHandle(&pChunk->aRefs[i].hClass, pPriorClass, NIL_RTLOCKVALCLASS, fDone);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pChunk->aRefs[i].fAutodidacticism = fAutodidacticism;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /* If no more chunks, allocate a new one and insert the class before linking it. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTLOCKVALCLASSREFCHUNK pNew = (PRTLOCKVALCLASSREFCHUNK)RTMemAlloc(sizeof(*pNew));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pNew->aRefs); i++)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pNew->aRefs[0].fAutodidacticism = fAutodidacticism;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync } /* chunk loop */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rc = !g_fLockValSoftWrongOrder ? VERR_SEM_LV_WRONG_ORDER : VINF_SUCCESS;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncRTDECL(int) RTLockValidatorClassAddPriorClass(RTLOCKVALCLASS hClass, RTLOCKVALCLASS hPriorClass)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertReturn(pClass->u32Magic == RTLOCKVALCLASS_MAGIC, VERR_INVALID_HANDLE);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertReturn(pPriorClass->u32Magic == RTLOCKVALCLASS_MAGIC, VERR_INVALID_HANDLE);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return rtLockValidatorClassAddPriorClass(pClass, pPriorClass, false /*fAutodidacticism*/, NULL);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncRTDECL(int) RTLockValidatorClassEnforceStrictReleaseOrder(RTLOCKVALCLASS hClass, bool fEnabled)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertReturn(pClass->u32Magic == RTLOCKVALCLASS_MAGIC, VERR_INVALID_HANDLE);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync ASMAtomicWriteBool(&pClass->fStrictReleaseOrder, fEnabled);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Unlinks all siblings.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * This is used during record deletion and assumes no races.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pCore One of the siblings.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncstatic void rtLockValidatorUnlinkAllSiblings(PRTLOCKVALRECCORE pCore)
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 pSibling = ASMAtomicXchgPtrT(ppCoreNext, NULL, PRTLOCKVALRECUNION);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncRTDECL(int) RTLockValidatorRecMakeSiblings(PRTLOCKVALRECCORE pRec1, PRTLOCKVALRECCORE pRec2)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Validate input.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertPtrReturn(p1, VERR_SEM_LV_INVALID_PARAMETER);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertReturn( p1->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertPtrReturn(p2, VERR_SEM_LV_INVALID_PARAMETER);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertReturn( p2->Core.u32Magic == RTLOCKVALRECEXCL_MAGIC
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Link them (circular list).
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync else if ( p1->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC
885ac2b8c00cb7f4878e9108f40e1a43ff756e35vboxsync AssertFailedReturn(VERR_SEM_LV_INVALID_PARAMETER); /* unsupported mix */
885ac2b8c00cb7f4878e9108f40e1a43ff756e35vboxsync * Gets the lock name for the given record.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @returns Read-only lock name.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pRec The lock record.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncDECL_FORCE_INLINE(const char *) rtLockValidatorRecName(PRTLOCKVALRECUNION pRec)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return pRec->ShrdOwner.pSharedRec ? pRec->ShrdOwner.pSharedRec->szName : "orphaned";
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pRec = rtLockValidatorReadRecUnionPtr(&pRec->Nest.pRec);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return pRec->ShrdOwner.pSharedRec ? pRec->ShrdOwner.pSharedRec->szName : "orphaned";
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return "unknown-nested";
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return "orphaned-nested";
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return "unknown";
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Gets the class for this locking record.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @returns Pointer to the class or NIL_RTLOCKVALCLASS.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * @param pRec The lock validator record.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncDECLINLINE(RTLOCKVALCLASSINT *) rtLockValidatorRecGetClass(PRTLOCKVALRECUNION pRec)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTLOCKVALRECSHRD pSharedRec = pRec->ShrdOwner.pSharedRec;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync && pSharedRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC))
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync PRTLOCKVALRECSHRD pSharedRec = pRealRec->ShrdOwner.pSharedRec;
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync && pSharedRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC))
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync AssertMsgFailed(("%p %p %#x\n", pRec, pRealRec, pRealRec->Core.u32Magic));
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync * Gets the class for this locking record and the pointer to the one below it in
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync * the stack.
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.
af8d59d05d72f134aeea62712f1286b369807d52vboxsyncrtLockValidatorRecGetClassesAndDown(PRTLOCKVALRECUNION pRec, uint32_t *puSubClass, PRTLOCKVALRECUNION *ppDown)
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync PRTLOCKVALRECSHRD pSharedRec = pRec->ShrdOwner.pSharedRec;
bf144aab354eaec8ee22b16b1c138f47f38b7244vboxsync && pSharedRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC))
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTLOCKVALRECSHRD pSharedRec = pRealRec->ShrdOwner.pSharedRec;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync && pSharedRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC))
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync AssertMsgFailed(("%p %p %#x\n", pRec, pRealRec, pRealRec->Core.u32Magic));
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync * Gets the sub-class for a lock record.
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync * @returns the sub-class.
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync * @param pRec The lock validator record.
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsyncDECLINLINE(uint32_t) rtLockValidatorRecGetSubClass(PRTLOCKVALRECUNION pRec)
bd810d58866067df322ea7f4a4627d9bdebb70d3vboxsync PRTLOCKVALRECSHRD pSharedRec = pRec->ShrdOwner.pSharedRec;
061bebe04c5bfa05ed733d2a1204389c2a0c96a8vboxsync && pSharedRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC))
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync PRTLOCKVALRECSHRD pSharedRec = pRealRec->ShrdOwner.pSharedRec;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync && pSharedRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC))
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync AssertMsgFailed(("%p %p %#x\n", pRec, pRealRec, pRealRec->Core.u32Magic));
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * Calculates the depth of a lock stack.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @returns Number of stack frames.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @param pThread The thread.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsyncstatic uint32_t rtLockValidatorStackDepth(PRTTHREADINT pThread)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync PRTLOCKVALRECUNION pCur = rtLockValidatorReadRecUnionPtr(&pThread->LockValidator.pStackTop);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pCur = rtLockValidatorReadRecUnionPtr(&pCur->Excl.pDown);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pCur = rtLockValidatorReadRecUnionPtr(&pCur->ShrdOwner.pDown);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync pCur = rtLockValidatorReadRecUnionPtr(&pCur->Nest.pDown);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync AssertMsgFailedReturn(("%#x\n", pCur->Core.u32Magic), cEntries);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * Checks if the stack contains @a pRec.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @returns true / false.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @param pThreadSelf The current thread.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @param pRec The lock record.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsyncstatic bool rtLockValidatorStackContainsRec(PRTTHREADINT pThreadSelf, PRTLOCKVALRECUNION pRec)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync PRTLOCKVALRECUNION pCur = pThreadSelf->LockValidator.pStackTop;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync return true;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync AssertMsgFailedReturn(("%#x\n", pCur->Core.u32Magic), false);
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync return false;
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync#endif /* RT_STRICT */
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * Pushes a lock record onto the stack.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @param pThreadSelf The current thread.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync * @param pRec The lock record.
6e7c344fc7cdb580356704e8201207b394d367bbvboxsyncstatic void rtLockValidatorStackPush(PRTTHREADINT pThreadSelf, PRTLOCKVALRECUNION pRec)
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync Assert(!rtLockValidatorStackContainsRec(pThreadSelf, pRec));
6e7c344fc7cdb580356704e8201207b394d367bbvboxsync rtLockValidatorWriteRecUnionPtr(&pRec->Excl.pDown, pThreadSelf->LockValidator.pStackTop);
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync rtLockValidatorWriteRecUnionPtr(&pRec->ShrdOwner.pDown, pThreadSelf->LockValidator.pStackTop);
509a2f53cb92e3bf060f4615936354188ce92836vboxsync AssertMsgFailedReturnVoid(("%#x\n", pRec->Core.u32Magic));
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync rtLockValidatorWriteRecUnionPtr(&pThreadSelf->LockValidator.pStackTop, pRec);
509a2f53cb92e3bf060f4615936354188ce92836vboxsync * Pops a lock record off the stack.
f11a163be74ca22a873fc5437f7e2cbf6ab7a564vboxsync * @param pThreadSelf The current thread.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * @param pRec The lock.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsyncstatic void rtLockValidatorStackPop(PRTTHREADINT pThreadSelf, PRTLOCKVALRECUNION pRec)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValidatorWriteRecUnionPtr(&pRec->Excl.pDown, NULL); /* lazy bird */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValidatorWriteRecUnionPtr(&pRec->ShrdOwner.pDown, NULL);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync AssertMsgFailedReturnVoid(("%#x\n", pRec->Core.u32Magic));
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValidatorWriteRecUnionPtr(&pThreadSelf->LockValidator.pStackTop, pDown);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync /* Find the pointer to our record and unlink ourselves. */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync PRTLOCKVALRECUNION pCur = pThreadSelf->LockValidator.pStackTop;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync AssertMsgFailedReturnVoid(("%#x\n", pCur->Core.u32Magic));
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Creates and pushes lock recursion record onto the stack.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * @param pThreadSelf The current thread.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * @param pRec The lock record.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * @param pSrcPos Where the recursion occurred.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsyncstatic void rtLockValidatorStackPushRecursion(PRTTHREADINT pThreadSelf, PRTLOCKVALRECUNION pRec, PCRTLOCKVALSRCPOS pSrcPos)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync Assert(rtLockValidatorStackContainsRec(pThreadSelf, pRec));
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Allocate a new recursion record
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync PRTLOCKVALRECNEST pRecursionRec = pThreadSelf->LockValidator.pFreeNestRecs;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pThreadSelf->LockValidator.pFreeNestRecs = pRecursionRec->pNextFree;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pRecursionRec = (PRTLOCKVALRECNEST)RTMemAlloc(sizeof(*pRecursionRec));
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Initialize it.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pRecursionRec->cRecursion = pRec->ShrdOwner.cRecursion;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValidatorSrcPosCopy(&pRecursionRec->SrcPos, pSrcPos);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pRecursionRec->Core.u32Magic = RTLOCKVALRECNEST_MAGIC;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pRecursionRec->pDown = pThreadSelf->LockValidator.pStackTop;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValidatorWriteRecUnionPtr(&pThreadSelf->LockValidator.pStackTop, (PRTLOCKVALRECUNION)pRecursionRec);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync#endif /* RTLOCKVAL_WITH_RECURSION_RECORDS */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Pops a lock recursion record off the stack.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * @param pThreadSelf The current thread.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * @param pRec The lock record.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsyncstatic void rtLockValidatorStackPopRecursion(PRTTHREADINT pThreadSelf, PRTLOCKVALRECUNION pRec)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync Assert(rtLockValidatorStackContainsRec(pThreadSelf, pRec));
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 * Pop the recursion record.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync PRTLOCKVALRECUNION pNest = pThreadSelf->LockValidator.pStackTop;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValidatorWriteRecUnionPtr(&pThreadSelf->LockValidator.pStackTop, pNest->Nest.pDown);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync /* Find the record above ours. */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync AssertMsgReturnVoid(pNest, ("%p %p\n", pRec, pThreadSelf));
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync AssertMsgFailedReturnVoid(("%#x\n", pNest->Core.u32Magic));
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync break; /* ugly */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValidatorWriteRecUnionPtr(ppDown, pNest->Nest.pDown);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Invalidate and free the record.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync ASMAtomicWriteU32(&pNest->Core.u32Magic, RTLOCKVALRECNEST_MAGIC);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValidatorWriteRecUnionPtr(&pNest->Nest.pDown, NULL);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync rtLockValidatorWriteRecUnionPtr(&pNest->Nest.pRec, NULL);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pNest->Nest.pNextFree = pThreadSelf->LockValidator.pFreeNestRecs;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync pThreadSelf->LockValidator.pFreeNestRecs = &pNest->Nest;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync#endif /* RTLOCKVAL_WITH_RECURSION_RECORDS */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Helper for rtLockValidatorStackCheckLockingOrder that does the bitching and
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * returns VERR_SEM_LV_WRONG_ORDER.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsyncstatic int rtLockValidatorStackWrongOrder(const char *pszWhat, PCRTLOCKVALSRCPOS pSrcPos, PRTTHREADINT pThreadSelf,
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync PRTLOCKVALRECUNION pRec1, PRTLOCKVALRECUNION pRec2,
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync RTLOCKVALCLASSINT *pClass1, RTLOCKVALCLASSINT *pClass2)
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 return !g_fLockValSoftWrongOrder ? VERR_SEM_LV_WRONG_ORDER : VINF_SUCCESS;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Checks if the sub-class order is ok or not.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Used to deal with two locks from the same class.
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
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsyncDECL_FORCE_INLINE(bool) rtLockValidatorIsSubClassOrderOk(uint32_t uSubClass1, uint32_t uSubClass2)
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync /* NONE kills ANY. */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync return false;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync return true;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync /* ANY counters all USER values. (uSubClass1 == NONE only if they are equal) */
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync AssertCompile(RTLOCKVAL_SUB_CLASS_ANY > RTLOCKVAL_SUB_CLASS_NONE);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync return true;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync return false;
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync * Checks if the class and sub-class lock order is ok.
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 * @param uSubClass2 The sub-class that goes with @a pClass2.
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsyncDECL_FORCE_INLINE(bool) rtLockValidatorIsClassOrderOk(RTLOCKVALCLASSINT *pClass1, uint32_t uSubClass1,
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync return rtLockValidatorIsSubClassOrderOk(uSubClass1, uSubClass2);
fdd5017195ab02e09ceefa312beaf5d538fdf2edvboxsync return rtLockValidatorClassIsPriorClass(pClass1, pClass2);
static int rtLockValidatorStackCheckLockingOrder2(RTLOCKVALCLASSINT * const pClass, uint32_t const uSubClass,
while (pCur)
RTLOCKVALCLASSINT *pPriorClass = rtLockValidatorRecGetClassesAndDown(pCur, &uPriorSubClass, &pDown);
cNewRules++;
int rc = rtLockValidatorClassAddPriorClass(pClass, pFirstBadClass, true /*fAutodidacticism*/, pSrcPos);
while (pCur)
RTLOCKVALCLASSINT *pPriorClass = rtLockValidatorRecGetClassesAndDown(pCur, &uPriorSubClass, &pDown);
while (pCur)
RTLOCKVALCLASSINT *pPriorClass = rtLockValidatorRecGetClassesAndDown(pCur, &uPriorSubClass, &pDown);
int rc = rtLockValidatorClassAddPriorClass(pClass, pPriorClass, true /*fAutodidacticism*/, pSrcPos);
return VINF_SUCCESS;
static int rtLockValidatorStackCheckLockingOrder(RTLOCKVALCLASSINT * const pClass, uint32_t const uSubClass,
if (!pCur)
return VINF_SUCCESS;
RTLOCKVALCLASSINT *pPriorClass = rtLockValidatorRecGetClassesAndDown(pCur, &uPriorSubClass, &pDown);
if (!pCur)
return VINF_SUCCESS;
|| ( pTop
return VINF_SUCCESS;
while (pTop)
DECL_FORCE_INLINE(bool) rtLockValidatorDdAreAllThreadsBlocked(PRTLOCKVALRECSHRD pRec, PRTTHREADINT pThreadSelf)
if (cEntries == 0)
if ( pEntry
if (!pCurThread)
if (--cEntries == 0)
return VERR_TRY_AGAIN;
return VERR_TRY_AGAIN;
return VERR_TRY_AGAIN;
return VERR_TRY_AGAIN;
return VERR_SEM_LV_ILLEGAL_UPGRADE;
return VERR_SEM_LV_DEADLOCK;
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;
static int rtLockValidatorDdDoDetection(PRTLOCKVALDDSTACK pStack, PRTLOCKVALRECUNION const pOriginalRec,
pStack->c = 0;
case RTLOCKVALRECEXCL_MAGIC:
if ( !pNextThread
if (!pNextRec)
if ( pRec
case RTLOCKVALRECSHRD_MAGIC:
if (pEntry)
if ( !pNextThread
if (pNextRec)
if (pNextRec)
if (pNextRec)
pStack->c++;
return VINF_SUCCESS;
if ( !pRec
pStack->c = i;
if ( !pThread
const char *pszWhat;
switch (rc)
rtLockValComplainFirst(pszWhat, pSrcPos, pThreadSelf, pStack->a[0].pRec != pRec ? pRec : NULL, true);
static int rtLockValidatorDeadlockDetection(PRTLOCKVALRECUNION pRec, PRTTHREADINT pThreadSelf, PCRTLOCKVALSRCPOS pSrcPos)
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return rc;
RTDECL(void) RTLockValidatorRecExclInitV(PRTLOCKVALRECEXCL pRec, RTLOCKVALCLASS hClass, uint32_t uSubClass,
if (pszNameFmt)
RTDECL(void) RTLockValidatorRecExclInit(PRTLOCKVALRECEXCL pRec, RTLOCKVALCLASS hClass, uint32_t uSubClass,
if (!pRec)
return VERR_NO_MEMORY;
return VINF_SUCCESS;
const char *pszNameFmt, ...)
return rc;
if (pRec)
if (!pRecU)
static void rtLockValidatorRecExclReleaseOwnerUnchecked(PRTLOCKVALRECUNION pRec, bool fFinalRecursion)
if (!pRecU)
return VINF_SUCCESS;
return VINF_SUCCESS;
return rc;
return VINF_SUCCESS;
if (!pRecU)
return VINF_SUCCESS;
return VINF_SUCCESS;
return VERR_SEM_LV_NESTED;
return VINF_SUCCESS;
return VINF_SUCCESS;
return rc;
return VINF_SUCCESS;
RTDECL(int) RTLockValidatorRecExclRecursionMixed(PRTLOCKVALRECEXCL pRec, PRTLOCKVALRECCORE pRecMixed, PCRTLOCKVALSRCPOS pSrcPos)
return VINF_SUCCESS;
return VERR_SEM_LV_NESTED;
return VINF_SUCCESS;
return VINF_SUCCESS;
return rc;
return VINF_SUCCESS;
if (!pRecU)
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
return rtLockValidatorStackCheckLockingOrder(pRecU->Excl.hClass, pRecU->Excl.uSubClass, hThreadSelf, pRecU, pSrcPos);
if (!pRecU)
return VINF_SUCCESS;
return VINF_SUCCESS;
if ( !fRecursiveOk
return rc;
RTDECL(int) RTLockValidatorRecExclCheckOrderAndBlocking(PRTLOCKVALRECEXCL pRec, RTTHREAD hThreadSelf,
return rc;
RTDECL(void) RTLockValidatorRecSharedInitV(PRTLOCKVALRECSHRD pRec, RTLOCKVALCLASS hClass, uint32_t uSubClass,
if (pszNameFmt)
RTDECL(void) RTLockValidatorRecSharedInit(PRTLOCKVALRECSHRD pRec, RTLOCKVALCLASS hClass, uint32_t uSubClass,
RTLockValidatorRecSharedInitV(pRec, hClass, uSubClass, hLock, fSignaller, fEnabled, pszNameFmt, va);
if (!pRec)
return VERR_NO_MEMORY;
RTLockValidatorRecSharedInitV(pRec, hClass, uSubClass, pvLock, fSignaller, fEnabled, pszNameFmt, va);
return VINF_SUCCESS;
const char *pszNameFmt, ...)
int rc = RTLockValidatorRecSharedCreateV(ppRec, hClass, uSubClass, pvLock, fSignaller, fEnabled, pszNameFmt, va);
return rc;
if (pRec)
if (papOwners)
PRTLOCKVALRECUNION pEntry = (PRTLOCKVALRECUNION)rtLockValidatorUoReadSharedOwner(&papOwners[iEntry]);
if (piEntry)
return pEntry;
return NULL;
return VINF_SUCCESS;
if (pEntry)
return VINF_SUCCESS;
return rtLockValidatorStackCheckLockingOrder(pRecU->Shared.hClass, pRecU->Shared.uSubClass, hThreadSelf, pRecU, pSrcPos);
return VINF_SUCCESS;
: NULL;
if (pEntry)
if ( !fRecursiveOk
return rc;
RTDECL(int) RTLockValidatorRecSharedCheckOrderAndBlocking(PRTLOCKVALRECSHRD pRec, RTTHREAD hThreadSelf,
return rc;
rtLockValidatorRecSharedAllocOwner(PRTLOCKVALRECSHRD pRec, PRTTHREADINT pThreadSelf, PCRTLOCKVALSRCPOS pSrcPos)
unsigned iEntry = ASMBitFirstSetU32(ASMAtomicUoReadU32(&pThreadSelf->LockValidator.bmFreeShrdOwners));
if ( iEntry > 0
return NULL;
if (pSrcPos)
return pEntry;
if (pEntry)
if (!papOwners)
while (cInc-- > 0)
cAllocated++;
DECLINLINE(bool) rtLockValidatorRecSharedAddOwner(PRTLOCKVALRECSHRD pShared, PRTLOCKVALRECSHRDOWN pEntry)
AssertFailed();
DECLINLINE(void) rtLockValidatorRecSharedRemoveAndFreeOwner(PRTLOCKVALRECSHRD pShared, PRTLOCKVALRECSHRDOWN pEntry,
AssertReturnVoidStmt(pShared->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC, rtLockValidatorSerializeDetectionLeave());
AssertFailed();
RTDECL(void) RTLockValidatorRecSharedResetOwner(PRTLOCKVALRECSHRD pRec, RTTHREAD hThread, PCRTLOCKVALSRCPOS pSrcPos)
AssertReturnVoidStmt(pRec->Core.u32Magic == RTLOCKVALRECSHRD_MAGIC, rtLockValidatorSerializeDetectionLeave());
if (pEntry)
iEntry++;
if ( pEntry
RTDECL(void) RTLockValidatorRecSharedAddOwner(PRTLOCKVALRECSHRD pRec, RTTHREAD hThread, PCRTLOCKVALSRCPOS pSrcPos)
if (pEntry)
if (pEntry)
return VINF_SUCCESS;
return VERR_SEM_LV_NOT_OWNER;
return rc;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VERR_SEM_LV_NOT_SIGNALLER;
return VINF_SUCCESS;
if (!pThread)
return VERR_INVALID_HANDLE;
return cWriteLocks;
if (!pThread)
return VERR_INVALID_HANDLE;
return cReadLocks;
if (pThread)
if (pRec)
case RTLOCKVALRECEXCL_MAGIC:
case RTLOCKVALRECSHRD_MAGIC:
return pvLock;
bool fRet = false;
if (pThread)
return fRet;
bool fRet = false;
if (pThread)
case RTLOCKVALRECEXCL_MAGIC:
case RTLOCKVALRECNEST_MAGIC:
case RTLOCKVALRECEXCL_MAGIC:
return fRet;
RTDECL(bool) RTLockValidatorHoldsLocksInSubClass(RTTHREAD hCurrentThread, RTLOCKVALCLASS hClass, uint32_t uSubClass)
bool fRet = false;
if (pThread)
case RTLOCKVALRECEXCL_MAGIC:
case RTLOCKVALRECNEST_MAGIC:
case RTLOCKVALRECEXCL_MAGIC:
return fRet;