Index: include/lldb/Host/Mutex.h =================================================================== --- include/lldb/Host/Mutex.h +++ include/lldb/Host/Mutex.h @@ -14,35 +14,62 @@ #include "lldb/lldb-types.h" #include -#ifdef LLDB_CONFIGURATION_DEBUG #include -#endif namespace lldb_private { -//---------------------------------------------------------------------- -/// @class Mutex Mutex.h "lldb/Host/Mutex.h" -/// @brief A C++ wrapper class for pthread mutexes. -//---------------------------------------------------------------------- -class Mutex +class MutexBase { public: - friend class Locker; - friend class Condition; - - enum Type - { - eMutexTypeNormal, ///< Mutex that can't recursively entered by the same thread - eMutexTypeRecursive ///< Mutex can be recursively entered by the same thread - }; + virtual ~MutexBase() = default; + + //------------------------------------------------------------------ + /// Lock the mutex. + /// + /// Locks the mutex owned by this object. If the mutex is already + /// locked, the calling thread will block until the mutex becomes + /// available. + /// + /// @return + /// The non-zero error code in case of error. + //------------------------------------------------------------------ + virtual int + Lock() = 0; //------------------------------------------------------------------ - /// @class Mutex::Locker + /// Try to lock the mutex. + /// + /// Attempts to lock the mutex owned by this object without blocking. + /// If the mutex is already locked, TryLock() will not block waiting + /// for the mutex, but will return an error condition. + /// + /// @return + /// The non-zero error code in case of error. + //------------------------------------------------------------------ + virtual int + TryLock(const char *failure_message = NULL) = 0; + + //------------------------------------------------------------------ + /// Unlock the mutex. + /// + /// If the current thread holds the lock on the owned mutex, then + /// Unlock() will unlock the mutex. Calling Unlock() on this object + /// when the calling thread does not hold the lock will result in + /// undefined behavior. + /// + /// @return + /// The non-zero error code in case of error. + //------------------------------------------------------------------ + virtual int + Unlock() = 0 ; + + //------------------------------------------------------------------ + /// @class MutexBase::Locker /// /// A scoped locking class that allows a variety of pthread mutex - /// objects to have a mutex locked when an Mutex::Locker + /// objects to have a mutex locked when an MutexBase::Locker /// object is created, and unlocked when it goes out of scope or - /// when the Mutex::Locker::Reset(pthread_mutex_t *) + /// when the MutexBase::Locker::Reset(pthread_mutex_t *) /// is called. This provides an exception safe way to lock a mutex /// in a scope. //------------------------------------------------------------------ @@ -54,38 +81,38 @@ /// /// This will create a scoped mutex locking object that doesn't /// have a mutex to lock. One will need to be provided using the - /// Mutex::Locker::Reset(pthread_mutex_t *) method. + /// MutexBase::Locker::Reset(pthread_mutex_t *) method. /// - /// @see Mutex::Locker::Reset(pthread_mutex_t *) + /// @see MutexBase::Locker::Reset(pthread_mutex_t *) //-------------------------------------------------------------- Locker(); //-------------------------------------------------------------- - /// Constructor with a Mutex object. + /// Constructor with a MutexBase object. /// /// This will create a scoped mutex locking object that extracts /// the mutex owned by \a m and locks it. /// /// @param[in] m - /// An instance of a Mutex object that contains a + /// An instance of a MutexBase object that contains a /// valid mutex object. //-------------------------------------------------------------- - Locker(Mutex& m); + Locker(MutexBase& m); //-------------------------------------------------------------- - /// Constructor with a Mutex object pointer. + /// Constructor with a MutexBase object pointer. /// /// This will create a scoped mutex locking object that extracts /// the mutex owned by a m and locks it. /// /// @param[in] m - /// A pointer to instance of a Mutex object that + /// A pointer to instance of a MutexBase object that /// contains a valid mutex object. //-------------------------------------------------------------- - Locker(Mutex* m); + Locker(MutexBase* m); //-------------------------------------------------------------- - /// Desstructor + /// Destructor /// /// Unlocks any valid pthread_mutex_t that this object may /// contain. @@ -100,10 +127,10 @@ /// non-NULL. //-------------------------------------------------------------- void - Lock (Mutex &mutex); + Lock (MutexBase &mutex); void - Lock (Mutex *mutex) + Lock (MutexBase *mutex) { if (mutex) Lock(*mutex); @@ -125,10 +152,10 @@ /// returns \b false otherwise. //-------------------------------------------------------------- bool - TryLock (Mutex &mutex, const char *failure_message = NULL); + TryLock (MutexBase &mutex, const char *failure_message = NULL); bool - TryLock (Mutex *mutex, const char *failure_message = NULL) + TryLock (MutexBase *mutex, const char *failure_message = NULL) { if (mutex) return TryLock(*mutex, failure_message); @@ -143,13 +170,28 @@ //-------------------------------------------------------------- /// Member variables //-------------------------------------------------------------- - Mutex *m_mutex_ptr; + MutexBase *m_mutex_ptr; private: Locker(const Locker&); const Locker& operator=(const Locker&); }; +}; +//---------------------------------------------------------------------- +/// @class Mutex Mutex.h "lldb/Host/Mutex.h" +/// @brief A C++ wrapper class for pthread mutexes. +//---------------------------------------------------------------------- +class Mutex : public MutexBase +{ +public: + friend class Condition; + + enum Type + { + eMutexTypeNormal, ///< Mutex that can't recursively entered by the same thread + eMutexTypeRecursive ///< Mutex can be recursively entered by the same thread + }; //------------------------------------------------------------------ /// Default constructor. @@ -178,59 +220,16 @@ /// /// Destroys the mutex owned by this object. //------------------------------------------------------------------ -#ifdef LLDB_CONFIGURATION_DEBUG - virtual -#endif ~Mutex(); - //------------------------------------------------------------------ - /// Lock the mutex. - /// - /// Locks the mutex owned by this object. If the mutex is already - /// locked, the calling thread will block until the mutex becomes - /// available. - /// - /// @return - /// The error code from \c pthread_mutex_lock(). - //------------------------------------------------------------------ -#ifdef LLDB_CONFIGURATION_DEBUG - virtual -#endif int - Lock(); + Lock() override; - //------------------------------------------------------------------ - /// Try to lock the mutex. - /// - /// Attempts to lock the mutex owned by this object without blocking. - /// If the mutex is already locked, TryLock() will not block waiting - /// for the mutex, but will return an error condition. - /// - /// @return - /// The error code from \c pthread_mutex_trylock(). - //------------------------------------------------------------------ -#ifdef LLDB_CONFIGURATION_DEBUG - virtual -#endif int - TryLock(const char *failure_message = NULL); + TryLock(const char *failure_message = NULL) override; - //------------------------------------------------------------------ - /// Unlock the mutex. - /// - /// If the current thread holds the lock on the owned mutex, then - /// Unlock() will unlock the mutex. Calling Unlock() on this object - /// when the calling thread does not hold the lock will result in - /// undefined behavior. - /// - /// @return - /// The error code from \c pthread_mutex_unlock(). - //------------------------------------------------------------------ -#ifdef LLDB_CONFIGURATION_DEBUG - virtual -#endif int - Unlock(); + Unlock() override; protected: //------------------------------------------------------------------ @@ -254,6 +253,47 @@ const Mutex& operator=(const Mutex&); }; +class NamedMutex : public MutexBase +{ +public: + // Full mutex name contains system-specific prefix and base_name: + // POSIX - "/$base_name" + // Windows - "Global\$base_name" + explicit NamedMutex(const char* base_name); + ~NamedMutex(); + + int + Lock() override; + + int + TryLock(const char *failure_message = NULL) override; + + int + Unlock() override; + + const std::string& + GetName() const + { + return m_name; + } + + // Returns max length of mutex name, -1 for unlimited. + static int + GetMaxNameLength(); + +protected: + //------------------------------------------------------------------ + // Member variables + //------------------------------------------------------------------ + const std::string m_name; + void* m_mutex; ///< The OS mutex object. + +private: + NamedMutex(const NamedMutex&); + const NamedMutex& operator=(const NamedMutex&); + +}; + #ifdef LLDB_CONFIGURATION_DEBUG class TrackingMutex : public Mutex { @@ -264,11 +304,11 @@ virtual ~TrackingMutex() {} - virtual int - Unlock (); + int + Unlock () override; - virtual int - TryLock (const char *failure_message = NULL) + int + TryLock (const char *failure_message = NULL) override { int return_value = Mutex::TryLock(); if (return_value != 0 && failure_message != NULL) @@ -293,14 +333,14 @@ virtual ~LoggingMutex() {} - virtual int - Lock (); + int + Lock () override; - virtual int - Unlock (); + int + Unlock () override; - virtual int - TryLock (const char *failure_message = NULL); + int + TryLock (const char *failure_message = NULL) override; protected: bool m_locked; }; Index: lldb.xcodeproj/project.pbxproj =================================================================== --- lldb.xcodeproj/project.pbxproj +++ lldb.xcodeproj/project.pbxproj @@ -109,6 +109,7 @@ 256CBDC11ADD11C000BC6CDC /* RegisterContextPOSIX_arm.h in Headers */ = {isa = PBXBuildFile; fileRef = 256CBDBF1ADD11C000BC6CDC /* RegisterContextPOSIX_arm.h */; }; 257E47171AA56C2000A62F81 /* ModuleCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 257E47151AA56C2000A62F81 /* ModuleCache.cpp */; }; 257E47181AA56C2000A62F81 /* ModuleCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 257E47161AA56C2000A62F81 /* ModuleCache.h */; }; + 25B67C351AE148020000D19B /* Mutex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 25B67C341AE148020000D19B /* Mutex.cpp */; }; 25EF23781AC09B3700908DF0 /* AdbClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 25EF23751AC09AD800908DF0 /* AdbClient.cpp */; }; 25EF23791AC09B4200908DF0 /* AdbClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 25EF23761AC09AD800908DF0 /* AdbClient.h */; }; 260157C61885F51C00F875CF /* libpanel.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 260157C41885F4FF00F875CF /* libpanel.dylib */; }; @@ -1254,6 +1255,7 @@ 256CBDBF1ADD11C000BC6CDC /* RegisterContextPOSIX_arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterContextPOSIX_arm.h; path = Utility/RegisterContextPOSIX_arm.h; sourceTree = ""; }; 257E47151AA56C2000A62F81 /* ModuleCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ModuleCache.cpp; path = source/Utility/ModuleCache.cpp; sourceTree = ""; }; 257E47161AA56C2000A62F81 /* ModuleCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ModuleCache.h; path = source/Utility/ModuleCache.h; sourceTree = ""; }; + 25B67C341AE148020000D19B /* Mutex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Mutex.cpp; sourceTree = ""; }; 25EF23751AC09AD800908DF0 /* AdbClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AdbClient.cpp; sourceTree = ""; }; 25EF23761AC09AD800908DF0 /* AdbClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AdbClient.h; sourceTree = ""; }; 260157C41885F4FF00F875CF /* libpanel.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpanel.dylib; path = /usr/lib/libpanel.dylib; sourceTree = ""; }; @@ -4846,6 +4848,7 @@ 3FDFDDC4199D37BE009756A7 /* posix */ = { isa = PBXGroup; children = ( + 25B67C341AE148020000D19B /* Mutex.cpp */, AFDFDFD019E34D3400EAE509 /* ConnectionFileDescriptorPosix.cpp */, 3FDFDDC5199D37ED009756A7 /* FileSystem.cpp */, 3FDFE53019A292F0009756A7 /* HostInfoPosix.cpp */, @@ -6378,6 +6381,7 @@ 266DFE9713FD656E00D0C574 /* OperatingSystem.cpp in Sources */, 26954EBE1401EE8B00294D09 /* DynamicRegisterInfo.cpp in Sources */, 26274FA714030F79006BA130 /* DynamicLoaderDarwinKernel.cpp in Sources */, + 25B67C351AE148020000D19B /* Mutex.cpp in Sources */, 94FA3DE01405D50400833217 /* ValueObjectConstResultChild.cpp in Sources */, 3FDFED2819BA6D96009756A7 /* HostThread.cpp in Sources */, 949ADF031406F648004833E1 /* ValueObjectConstResultImpl.cpp in Sources */, Index: source/Host/CMakeLists.txt =================================================================== --- source/Host/CMakeLists.txt +++ source/Host/CMakeLists.txt @@ -72,6 +72,7 @@ posix/HostInfoPosix.cpp posix/HostProcessPosix.cpp posix/HostThreadPosix.cpp + posix/Mutex.cpp posix/PipePosix.cpp ) Index: source/Host/common/Mutex.cpp =================================================================== --- source/Host/common/Mutex.cpp +++ source/Host/common/Mutex.cpp @@ -16,77 +16,6 @@ #include #include -#if 0 -// This logging is way too verbose to enable even for a log channel. -// This logging can be enabled by changing the "#if 0", but should be -// reverted prior to checking in. -#include -#define DEBUG_LOG(fmt, ...) printf(fmt, ## __VA_ARGS__) -#else -#define DEBUG_LOG(fmt, ...) -#endif - -// Enable extra mutex error checking -#ifdef LLDB_CONFIGURATION_DEBUG -#define ENABLE_MUTEX_ERROR_CHECKING 1 -#include -#endif - -#if ENABLE_MUTEX_ERROR_CHECKING -#include - -enum MutexAction -{ - eMutexActionInitialized, - eMutexActionDestroyed, - eMutexActionAssertInitialized -}; - -static bool -error_check_mutex (pthread_mutex_t *m, MutexAction action) -{ - typedef std::set mutex_set; - static pthread_mutex_t g_mutex_set_mutex = PTHREAD_MUTEX_INITIALIZER; - static mutex_set g_initialized_mutex_set; - static mutex_set g_destroyed_mutex_set; - - bool success = true; - int err; - // Manually call lock so we don't to any of this error checking - err = ::pthread_mutex_lock (&g_mutex_set_mutex); - assert(err == 0); - switch (action) - { - case eMutexActionInitialized: - // Make sure this isn't already in our initialized mutex set... - assert (g_initialized_mutex_set.find(m) == g_initialized_mutex_set.end()); - // Remove this from the destroyed set in case it was ever in there - g_destroyed_mutex_set.erase(m); - // Add the mutex to the initialized set - g_initialized_mutex_set.insert(m); - break; - - case eMutexActionDestroyed: - // Make sure this isn't already in our destroyed mutex set... - assert (g_destroyed_mutex_set.find(m) == g_destroyed_mutex_set.end()); - // Remove this from the initialized so we can put it into the destroyed set - g_initialized_mutex_set.erase(m); - // Add the mutex to the destroyed set - g_destroyed_mutex_set.insert(m); - break; - case eMutexActionAssertInitialized: - // This function will return true if "m" is in the initialized mutex set - success = g_initialized_mutex_set.find(m) != g_initialized_mutex_set.end(); - assert (success); - break; - } - // Manually call unlock so we don't to any of this error checking - err = ::pthread_mutex_unlock (&g_mutex_set_mutex); - assert(err == 0); - return success; -} - -#endif using namespace lldb_private; @@ -97,7 +26,7 @@ // a mutex to lock. One will need to be provided using the Reset() // method. //---------------------------------------------------------------------- -Mutex::Locker::Locker () : +MutexBase::Locker::Locker () : m_mutex_ptr(NULL) { } @@ -108,19 +37,19 @@ // This will create a scoped mutex locking object that extracts the // mutex owned by "m" and locks it. //---------------------------------------------------------------------- -Mutex::Locker::Locker (Mutex& m) : +MutexBase::Locker::Locker (MutexBase& m) : m_mutex_ptr(NULL) { Lock (m); } //---------------------------------------------------------------------- -// Constructor with a Mutex object pointer. +// Constructor with a MutexBase object pointer. // // This will create a scoped mutex locking object that extracts the // mutex owned by "m" and locks it. //---------------------------------------------------------------------- -Mutex::Locker::Locker (Mutex* m) : +MutexBase::Locker::Locker (MutexBase* m) : m_mutex_ptr(NULL) { if (m) @@ -132,7 +61,7 @@ // // Unlocks any owned mutex object (if it is valid). //---------------------------------------------------------------------- -Mutex::Locker::~Locker () +MutexBase::Locker::~Locker () { Unlock(); } @@ -142,7 +71,7 @@ // mutex) and lock the new "mutex" object if it is non-NULL. //---------------------------------------------------------------------- void -Mutex::Locker::Lock (Mutex &mutex) +MutexBase::Locker::Lock (MutexBase &mutex) { // We already have this mutex locked or both are NULL... if (m_mutex_ptr == &mutex) @@ -155,7 +84,7 @@ } void -Mutex::Locker::Unlock () +MutexBase::Locker::Unlock () { if (m_mutex_ptr) { @@ -165,7 +94,7 @@ } bool -Mutex::Locker::TryLock (Mutex &mutex, const char *failure_message) +MutexBase::Locker::TryLock (MutexBase &mutex, const char *failure_message) { // We already have this mutex locked! if (m_mutex_ptr == &mutex) @@ -179,167 +108,6 @@ return m_mutex_ptr != NULL; } -#ifndef _WIN32 - -//---------------------------------------------------------------------- -// Default constructor. -// -// Creates a pthread mutex with no attributes. -//---------------------------------------------------------------------- -Mutex::Mutex () : - m_mutex() -{ - int err; - err = ::pthread_mutex_init (&m_mutex, NULL); -#if ENABLE_MUTEX_ERROR_CHECKING - if (err == 0) - error_check_mutex (&m_mutex, eMutexActionInitialized); -#endif - assert(err == 0); -} - -//---------------------------------------------------------------------- -// Default constructor. -// -// Creates a pthread mutex with "type" as the mutex type. -//---------------------------------------------------------------------- -Mutex::Mutex (Mutex::Type type) : - m_mutex() -{ - int err; - ::pthread_mutexattr_t attr; - err = ::pthread_mutexattr_init (&attr); - assert(err == 0); - switch (type) - { - case eMutexTypeNormal: -#if ENABLE_MUTEX_ERROR_CHECKING - err = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_ERRORCHECK); -#else - err = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_NORMAL); -#endif - break; - - case eMutexTypeRecursive: - err = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE); - break; - } - assert(err == 0); - err = ::pthread_mutex_init (&m_mutex, &attr); -#if ENABLE_MUTEX_ERROR_CHECKING - if (err == 0) - error_check_mutex (&m_mutex, eMutexActionInitialized); -#endif - assert(err == 0); - err = ::pthread_mutexattr_destroy (&attr); - assert(err == 0); -} - -//---------------------------------------------------------------------- -// Destructor. -// -// Destroys the mutex owned by this object. -//---------------------------------------------------------------------- -Mutex::~Mutex() -{ -#if ENABLE_MUTEX_ERROR_CHECKING - int err = ::pthread_mutex_destroy (&m_mutex); - assert(err == 0); - if (err == 0) - error_check_mutex (&m_mutex, eMutexActionDestroyed); - else - { - Host::SetCrashDescriptionWithFormat ("%s error: pthread_mutex_destroy() => err = %i (%s)", __PRETTY_FUNCTION__, err, strerror(err)); - assert(err == 0); - } - memset (&m_mutex, '\xba', sizeof(m_mutex)); -#else - ::pthread_mutex_destroy (&m_mutex); -#endif -} - -//---------------------------------------------------------------------- -// Locks the mutex owned by this object, if the mutex is already -// locked, the calling thread will block until the mutex becomes -// available. -// -// RETURNS -// The error code from the pthread_mutex_lock() function call. -//---------------------------------------------------------------------- -int -Mutex::Lock() -{ - DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] pthread_mutex_lock (%p)...\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), &m_mutex); - -#if ENABLE_MUTEX_ERROR_CHECKING - error_check_mutex (&m_mutex, eMutexActionAssertInitialized); -#endif - - int err = ::pthread_mutex_lock (&m_mutex); - - -#if ENABLE_MUTEX_ERROR_CHECKING - if (err) - { - Host::SetCrashDescriptionWithFormat ("%s error: pthread_mutex_lock(%p) => err = %i (%s)", __PRETTY_FUNCTION__, &m_mutex, err, strerror(err)); - assert(err == 0); - } -#endif - DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] pthread_mutex_lock (%p) => %i\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), &m_mutex, err); - return err; -} - -//---------------------------------------------------------------------- -// Attempts to lock the mutex owned by this object without blocking. -// If the mutex is already locked, TryLock() will not block waiting -// for the mutex, but will return an error condition. -// -// RETURNS -// The error code from the pthread_mutex_trylock() function call. -//---------------------------------------------------------------------- -int -Mutex::TryLock(const char *failure_message) -{ -#if ENABLE_MUTEX_ERROR_CHECKING - error_check_mutex (&m_mutex, eMutexActionAssertInitialized); -#endif - - int err = ::pthread_mutex_trylock (&m_mutex); - DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] pthread_mutex_trylock (%p) => %i\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), &m_mutex, err); - return err; -} - -//---------------------------------------------------------------------- -// If the current thread holds the lock on the owned mutex, then -// Unlock() will unlock the mutex. Calling Unlock() on this object -// that the calling thread does not hold will result in undefined -// behavior. -// -// RETURNS -// The error code from the pthread_mutex_unlock() function call. -//---------------------------------------------------------------------- -int -Mutex::Unlock() -{ -#if ENABLE_MUTEX_ERROR_CHECKING - error_check_mutex (&m_mutex, eMutexActionAssertInitialized); -#endif - - int err = ::pthread_mutex_unlock (&m_mutex); - -#if ENABLE_MUTEX_ERROR_CHECKING - if (err) - { - Host::SetCrashDescriptionWithFormat ("%s error: pthread_mutex_unlock(%p) => err = %i (%s)", __PRETTY_FUNCTION__, &m_mutex, err, strerror(err)); - assert(err == 0); - } -#endif - DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] pthread_mutex_unlock (%p) => %i\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), &m_mutex, err); - return err; -} - -#endif - //---------------------------------------------------------------------- // Mutex get accessor. //---------------------------------------------------------------------- Index: source/Host/posix/Mutex.cpp =================================================================== --- /dev/null +++ source/Host/posix/Mutex.cpp @@ -0,0 +1,384 @@ +//===-- Mutex.cpp -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/Mutex.h" +#include "lldb/Host/Host.h" +#include "lldb/Core/Log.h" + +#include + +#include +#include +#include + +using namespace lldb_private; + +#if 0 +// This logging is way too verbose to enable even for a log channel. +// This logging can be enabled by changing the "#if 0", but should be +// reverted prior to checking in. +#include +#define DEBUG_LOG(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else +#define DEBUG_LOG(fmt, ...) +#endif + +// Enable extra mutex error checking +#ifdef LLDB_CONFIGURATION_DEBUG +#define ENABLE_MUTEX_ERROR_CHECKING 1 +#include +#endif + +#if ENABLE_MUTEX_ERROR_CHECKING +#include + +enum MutexAction +{ + eMutexActionInitialized, + eMutexActionDestroyed, + eMutexActionAssertInitialized +}; + +static bool +error_check_mutex (pthread_mutex_t *m, MutexAction action) +{ + typedef std::set mutex_set; + static pthread_mutex_t g_mutex_set_mutex = PTHREAD_MUTEX_INITIALIZER; + static mutex_set g_initialized_mutex_set; + static mutex_set g_destroyed_mutex_set; + + bool success = true; + int err; + // Manually call lock so we don't to any of this error checking + err = ::pthread_mutex_lock (&g_mutex_set_mutex); + assert(err == 0); + switch (action) + { + case eMutexActionInitialized: + // Make sure this isn't already in our initialized mutex set... + assert (g_initialized_mutex_set.find(m) == g_initialized_mutex_set.end()); + // Remove this from the destroyed set in case it was ever in there + g_destroyed_mutex_set.erase(m); + // Add the mutex to the initialized set + g_initialized_mutex_set.insert(m); + break; + + case eMutexActionDestroyed: + // Make sure this isn't already in our destroyed mutex set... + assert (g_destroyed_mutex_set.find(m) == g_destroyed_mutex_set.end()); + // Remove this from the initialized so we can put it into the destroyed set + g_initialized_mutex_set.erase(m); + // Add the mutex to the destroyed set + g_destroyed_mutex_set.insert(m); + break; + case eMutexActionAssertInitialized: + // This function will return true if "m" is in the initialized mutex set + success = g_initialized_mutex_set.find(m) != g_initialized_mutex_set.end(); + assert (success); + break; + } + // Manually call unlock so we don't to any of this error checking + err = ::pthread_mutex_unlock (&g_mutex_set_mutex); + assert(err == 0); + return success; +} + +#endif + +//---------------------------------------------------------------------- +// Default constructor. +// +// Creates a pthread mutex with no attributes. +//---------------------------------------------------------------------- +Mutex::Mutex () : + m_mutex() +{ + int err; + err = ::pthread_mutex_init (&m_mutex, NULL); +#if ENABLE_MUTEX_ERROR_CHECKING + if (err == 0) + error_check_mutex (&m_mutex, eMutexActionInitialized); +#endif + assert(err == 0); +} + +//---------------------------------------------------------------------- +// Default constructor. +// +// Creates a pthread mutex with "type" as the mutex type. +//---------------------------------------------------------------------- +Mutex::Mutex (Mutex::Type type) : + m_mutex() +{ + int err; + ::pthread_mutexattr_t attr; + err = ::pthread_mutexattr_init (&attr); + assert(err == 0); + switch (type) + { + case eMutexTypeNormal: +#if ENABLE_MUTEX_ERROR_CHECKING + err = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_ERRORCHECK); +#else + err = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_NORMAL); +#endif + break; + + case eMutexTypeRecursive: + err = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE); + break; + } + assert(err == 0); + err = ::pthread_mutex_init (&m_mutex, &attr); +#if ENABLE_MUTEX_ERROR_CHECKING + if (err == 0) + error_check_mutex (&m_mutex, eMutexActionInitialized); +#endif + assert(err == 0); + err = ::pthread_mutexattr_destroy (&attr); + assert(err == 0); +} + +//---------------------------------------------------------------------- +// Destructor. +// +// Destroys the mutex owned by this object. +//---------------------------------------------------------------------- +Mutex::~Mutex() +{ +#if ENABLE_MUTEX_ERROR_CHECKING + int err = ::pthread_mutex_destroy (&m_mutex); + assert(err == 0); + if (err == 0) + error_check_mutex (&m_mutex, eMutexActionDestroyed); + else + { + Host::SetCrashDescriptionWithFormat ("%s error: pthread_mutex_destroy() => err = %i (%s)", __PRETTY_FUNCTION__, err, strerror(err)); + assert(err == 0); + } + memset (&m_mutex, '\xba', sizeof(m_mutex)); +#else + ::pthread_mutex_destroy (&m_mutex); +#endif +} + +//---------------------------------------------------------------------- +// Locks the mutex owned by this object, if the mutex is already +// locked, the calling thread will block until the mutex becomes +// available. +// +// RETURNS +// The error code from the pthread_mutex_lock() function call. +//---------------------------------------------------------------------- +int +Mutex::Lock() +{ + DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] pthread_mutex_lock (%p)...\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), &m_mutex); + +#if ENABLE_MUTEX_ERROR_CHECKING + error_check_mutex (&m_mutex, eMutexActionAssertInitialized); +#endif + + int err = ::pthread_mutex_lock (&m_mutex); + + +#if ENABLE_MUTEX_ERROR_CHECKING + if (err) + { + Host::SetCrashDescriptionWithFormat ("%s error: pthread_mutex_lock(%p) => err = %i (%s)", __PRETTY_FUNCTION__, &m_mutex, err, strerror(err)); + assert(err == 0); + } +#endif + DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] pthread_mutex_lock (%p) => %i\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), &m_mutex, err); + return err; +} + +//---------------------------------------------------------------------- +// Attempts to lock the mutex owned by this object without blocking. +// If the mutex is already locked, TryLock() will not block waiting +// for the mutex, but will return an error condition. +// +// RETURNS +// The error code from the pthread_mutex_trylock() function call. +//---------------------------------------------------------------------- +int +Mutex::TryLock(const char *failure_message) +{ +#if ENABLE_MUTEX_ERROR_CHECKING + error_check_mutex (&m_mutex, eMutexActionAssertInitialized); +#endif + + int err = ::pthread_mutex_trylock (&m_mutex); + DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] pthread_mutex_trylock (%p) => %i\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), &m_mutex, err); + return err; +} + +//---------------------------------------------------------------------- +// If the current thread holds the lock on the owned mutex, then +// Unlock() will unlock the mutex. Calling Unlock() on this object +// that the calling thread does not hold will result in undefined +// behavior. +// +// RETURNS +// The error code from the pthread_mutex_unlock() function call. +//---------------------------------------------------------------------- +int +Mutex::Unlock() +{ +#if ENABLE_MUTEX_ERROR_CHECKING + error_check_mutex (&m_mutex, eMutexActionAssertInitialized); +#endif + + int err = ::pthread_mutex_unlock (&m_mutex); + +#if ENABLE_MUTEX_ERROR_CHECKING + if (err) + { + Host::SetCrashDescriptionWithFormat ("%s error: pthread_mutex_unlock(%p) => err = %i (%s)", __PRETTY_FUNCTION__, &m_mutex, err, strerror(err)); + assert(err == 0); + } +#endif + DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] pthread_mutex_unlock (%p) => %i\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), &m_mutex, err); + return err; +} + +namespace +{ + +const int kInvalidMutex = -1; +const int kDefaultMaxNameLen = 29; + +sem_t* getSemaphore(void* sem_handle) +{ + return reinterpret_cast(sem_handle); +} + +std::string createSemaphoreName(const char* base_name) +{ + std::ostringstream name; + name << "/" << base_name; + return name.str(); +} + +} // namespace + +NamedMutex::NamedMutex(const char* base_name): + m_name(createSemaphoreName(base_name)), + m_mutex(nullptr) +{ + sem_t* sem = ::sem_open(m_name.c_str(), O_CREAT, 0660, 1); + if (sem == SEM_FAILED) + { +#if ENABLE_MUTEX_ERROR_CHECKING + Host::SetCrashDescriptionWithFormat ("%s error: sem_open(%s) => err = %s", __PRETTY_FUNCTION__, m_name.c_str(), ::strerror(errno)); + assert(sem != SEM_FAILED); +#endif + } + else + m_mutex = sem; + + DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] sem_open (%s) => %p\n", + Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), m_name.c_str(), m_mutex); +} + +NamedMutex::~NamedMutex() +{ + if (m_mutex != nullptr) + { + int err = ::sem_close(getSemaphore(m_mutex)); +#if ENABLE_MUTEX_ERROR_CHECKING + if (err != 0) + { + Host::SetCrashDescriptionWithFormat ("%s error: sem_close(%p) => err = %s", __PRETTY_FUNCTION__, m_mutex, ::strerror(errno)); + assert(err == 0); + } +#endif + DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] sem_close (%p) => %i\n", + Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), m_mutex, err); + + m_mutex = nullptr; + err = ::sem_unlink(m_name.c_str()); +#if ENABLE_MUTEX_ERROR_CHECKING + if (err != 0) + { + Host::SetCrashDescriptionWithFormat ("%s error: sem_unlink(%s) => err = %s", __PRETTY_FUNCTION__, m_name.c_str(), ::strerror(errno)); + assert(err == 0); + } +#endif + DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] sem_unlink (%s) => %i\n", + Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), m_name.c_str(), err); + } +} + +int +NamedMutex::Lock() +{ + if (m_mutex == nullptr) + return kInvalidMutex; + + int err = ::sem_wait(getSemaphore(m_mutex)); +#if ENABLE_MUTEX_ERROR_CHECKING + if (err != 0) + { + Host::SetCrashDescriptionWithFormat ("%s error: sem_wait(%p) => err = %s", __PRETTY_FUNCTION__, m_mutex, ::strerror(errno)); + assert(err == 0); + } +#endif + + DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] sem_wait (%p) => %i\n", + Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), m_mutex, err); + + return err; +} + +int +NamedMutex::TryLock(const char *failure_message) +{ + if (m_mutex == nullptr) + return kInvalidMutex; + + int err = ::sem_trywait(getSemaphore(m_mutex)); +#if ENABLE_MUTEX_ERROR_CHECKING + if (err != 0) + { + Host::SetCrashDescriptionWithFormat ("%s error: sem_wait(%p) => err = %s", __PRETTY_FUNCTION__, m_mutex, ::strerror(errno)); + assert(err == 0); + } +#endif + DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] sem_trywait (%p) => %i\n", + Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), m_mutex, err); + + return err; +} + +int +NamedMutex::Unlock() +{ + if (m_mutex == nullptr) + return kInvalidMutex; + + int err = ::sem_post(getSemaphore(m_mutex)); +#if ENABLE_MUTEX_ERROR_CHECKING + if (err != 0) + { + Host::SetCrashDescriptionWithFormat ("%s error: sem_post(%p) => err = %s", __PRETTY_FUNCTION__, m_mutex, ::strerror(errno)); + assert(err == 0); + } +#endif + DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] sem_post (%p) => %i\n", + Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), m_mutex, err); + + return err; +} + +int +NamedMutex::GetMaxNameLength() +{ + return kDefaultMaxNameLen; +} Index: source/Host/windows/Mutex.cpp =================================================================== --- source/Host/windows/Mutex.cpp +++ source/Host/windows/Mutex.cpp @@ -11,6 +11,7 @@ #include "lldb/Host/Host.h" #include "lldb/Host/windows/windows.h" +#include #include #include @@ -107,3 +108,102 @@ LeaveCriticalSection(static_cast(m_mutex)); return 0; } + +namespace +{ + +const int kInvalidMutex = -1; +const char* kNamePrefix = "Global\\"; + +HANDLE getHandle(void* mutex_handle) +{ + return reinterpret_cast(mutex_handle); +} + +std::string createMutexName(const char* base_name) +{ + std::ostringstream name; + name << kNamePrefix << base_name; + return name.str(); +} + +} // namespace + +NamedMutex::NamedMutex(const char* base_name): + m_name(createMutexName(base_name)), + m_mutex(nullptr) +{ + HANDLE h_mutex = ::CreateMutex(nullptr, TRUE, m_name.c_str()); + if (h_mutex != NULL) + m_mutex = h_mutex; + + DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] CreateMutex (%s) => %p\n", + Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), m_name.c_str(), m_mutex); +} + +NamedMutex::~NamedMutex() +{ + if (m_mutex != nullptr) + { + DWORD err = 0; + if (!::CloseHandle(getHandle(m_mutex))) + err = ::GetLastError(); + DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] CloseHandle (%p) => %d\n", + Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), m_mutex, err); + + m_mutex = nullptr; + } +} + +int +NamedMutex::Lock() +{ + if (m_mutex == nullptr) + return kInvalidMutex; + + int err = 0; + if (::WaitForSingleObject(getHandle(m_mutex), INFINITE) != WAIT_OBJECT_0) + err = ::GetLastError(); + + DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] WaitForSingleObject (%p, INFINITE) => %d\n", + Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), m_mutex, err); + + return err; +} + +int +NamedMutex::TryLock(const char *failure_message) +{ + if (m_mutex == nullptr) + return kInvalidMutex; + + int err = 0; + if (::WaitForSingleObject(getHandle(m_mutex), 0) != WAIT_OBJECT_0) + err = ::GetLastError(); + + DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] WaitForSingleObject (%p, 0) => %d\n", + Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), m_mutex, err); + + return err; +} + +int +NamedMutex::Unlock() +{ + if (m_mutex == nullptr) + return kInvalidMutex; + + DWORD err = 0; + if (!::ReleaseMutex(getHandle(m_mutex))) + err = ::GetLastError(); + DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] ReleaseMutex (%p) => %d\n", + Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), m_mutex, err); + + return err; +} + +int +NamedMutex::GetMaxNameLength() +{ + return MAX_PATH - strlen(kNamePrefix); +} Index: source/Utility/ModuleCache.cpp =================================================================== --- source/Utility/ModuleCache.cpp +++ source/Utility/ModuleCache.cpp @@ -12,6 +12,7 @@ #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Host/FileSystem.h" +#include "lldb/Host/Mutex.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FileUtilities.h" @@ -127,6 +128,16 @@ lldb::ModuleSP &cached_module_sp, bool *did_create_ptr) { + // Get named mutex lock by module UUID. + std::string mutex_name = module_spec.GetUUID ().GetAsString (""); + // Named mutex name may have length limitations - prune a name if it exceeds max size. + const auto mutex_max_len = NamedMutex::GetMaxNameLength(); + if (mutex_max_len > 0 && mutex_max_len < mutex_name.size()) + mutex_name = mutex_name.substr(0, mutex_max_len); + + NamedMutex module_mutex(mutex_name.c_str ()); + NamedMutex::Locker lock(module_mutex); + // Check local cache for a module. auto error = Get (root_dir_spec, hostname,