blob: 496dd0496c13042ced0ef1397c6ca62f3cbcbc5b [file] [log] [blame]
//===-- Mutex.h -------------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_Mutex_h_
#define liblldb_Mutex_h_
#if defined(__cplusplus)
#include "lldb/lldb-types.h"
#include <assert.h>
#ifdef LLDB_CONFIGURATION_DEBUG
#include <string>
#endif
namespace lldb_private {
//----------------------------------------------------------------------
/// @class Mutex Mutex.h "lldb/Host/Mutex.h"
/// @brief A C++ wrapper class for pthread mutexes.
//----------------------------------------------------------------------
class Mutex
{
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
};
//------------------------------------------------------------------
/// @class Mutex::Locker
///
/// A scoped locking class that allows a variety of pthread mutex
/// objects to have a mutex locked when an Mutex::Locker
/// object is created, and unlocked when it goes out of scope or
/// when the Mutex::Locker::Reset(pthread_mutex_t *)
/// is called. This provides an exception safe way to lock a mutex
/// in a scope.
//------------------------------------------------------------------
class Locker
{
public:
//--------------------------------------------------------------
/// Default constructor.
///
/// 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.
///
/// @see Mutex::Locker::Reset(pthread_mutex_t *)
//--------------------------------------------------------------
Locker();
//--------------------------------------------------------------
/// Constructor with a Mutex 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
/// valid mutex object.
//--------------------------------------------------------------
Locker(Mutex& m);
//--------------------------------------------------------------
/// Constructor with a Mutex 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
/// contains a valid mutex object.
//--------------------------------------------------------------
Locker(Mutex* m);
//--------------------------------------------------------------
/// Desstructor
///
/// Unlocks any valid pthread_mutex_t that this object may
/// contain.
//--------------------------------------------------------------
~Locker();
//--------------------------------------------------------------
/// Change the contained mutex.
///
/// Unlock the current mutex in this object (if it contains a
/// valid mutex) and lock the new \a mutex object if it is
/// non-NULL.
//--------------------------------------------------------------
void
Lock (Mutex &mutex);
void
Lock (Mutex *mutex)
{
if (mutex)
Lock(*mutex);
}
//--------------------------------------------------------------
/// Change the contained mutex only if the mutex can be locked.
///
/// Unlock the current mutex in this object (if it contains a
/// valid mutex) and try to lock \a mutex. If \a mutex can be
/// locked this object will take ownership of the lock and will
/// unlock it when it goes out of scope or Reset or TryLock are
/// called again. If the mutex is already locked, this object
/// will not take ownership of the mutex.
///
/// @return
/// Returns \b true if the lock was aquired and the this
/// object will unlock the mutex when it goes out of scope,
/// returns \b false otherwise.
//--------------------------------------------------------------
bool
TryLock (Mutex &mutex, const char *failure_message = NULL);
bool
TryLock (Mutex *mutex, const char *failure_message = NULL)
{
if (mutex)
return TryLock(*mutex, failure_message);
else
return false;
}
void
Unlock ();
protected:
//--------------------------------------------------------------
/// Member variables
//--------------------------------------------------------------
Mutex *m_mutex_ptr;
private:
Locker(const Locker&);
const Locker& operator=(const Locker&);
};
//------------------------------------------------------------------
/// Default constructor.
///
/// Creates a pthread mutex with no attributes.
//------------------------------------------------------------------
Mutex();
//------------------------------------------------------------------
/// Default constructor.
///
/// Creates a pthread mutex with \a type as the mutex type.
/// Valid values for \a type include:
/// @li Mutex::Type::eMutexTypeNormal
/// @li Mutex::Type::eMutexTypeRecursive
///
/// @param[in] type
/// The type of the mutex.
///
/// @see ::pthread_mutexattr_settype()
//------------------------------------------------------------------
Mutex(Mutex::Type type);
//------------------------------------------------------------------
/// Destructor.
///
/// 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();
//------------------------------------------------------------------
/// 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);
//------------------------------------------------------------------
/// 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();
protected:
//------------------------------------------------------------------
// Member variables
//------------------------------------------------------------------
// TODO: Hide the mutex in the implementation file in case we ever need to port to an
// architecture that doesn't have pthread mutexes.
lldb::mutex_t m_mutex; ///< The OS mutex object.
private:
//------------------------------------------------------------------
/// Mutex get accessor.
///
/// @return
/// A pointer to the pthread mutex object owned by this object.
//------------------------------------------------------------------
lldb::mutex_t *
GetMutex();
Mutex(const Mutex&);
const Mutex& operator=(const Mutex&);
};
#ifdef LLDB_CONFIGURATION_DEBUG
class TrackingMutex : public Mutex
{
public:
TrackingMutex() : Mutex() {}
TrackingMutex(Mutex::Type type) : Mutex (type) {}
virtual
~TrackingMutex() {}
virtual int
Unlock ();
virtual int
TryLock (const char *failure_message = NULL)
{
int return_value = Mutex::TryLock();
if (return_value != 0 && failure_message != NULL)
{
m_failure_message.assign(failure_message);
m_thread_that_tried = pthread_self();
}
return return_value;
}
protected:
pthread_t m_thread_that_tried;
std::string m_failure_message;
};
class LoggingMutex : public Mutex
{
public:
LoggingMutex() : Mutex(),m_locked(false) {}
LoggingMutex(Mutex::Type type) : Mutex (type),m_locked(false) {}
virtual
~LoggingMutex() {}
virtual int
Lock ();
virtual int
Unlock ();
virtual int
TryLock (const char *failure_message = NULL);
protected:
bool m_locked;
};
#endif
} // namespace lldb_private
#endif // #if defined(__cplusplus)
#endif