1
0
mirror of https://github.com/Zygo/bees.git synced 2025-05-17 21:35:45 +02:00

crucible: lockset: track lockers and use handle type [bees master branch edition]

Keep track of the locking thread so we can see why we are deadlocked
in gdb.

Use a handle type for locks based on shared_ptr.  Change the handle type
name to flush out any non-auto local variables.

Signed-off-by: Zygo Blaxell <bees@furryterror.org>
(cherry picked from commit aa0b22d445664409c36503c6fd808bc49b6816d0)
This commit is contained in:
Zygo Blaxell 2017-03-30 00:35:59 -04:00
parent 3901962379
commit 4f66d1cb44

View File

@ -2,14 +2,16 @@
#define CRUCIBLE_LOCKSET_H #define CRUCIBLE_LOCKSET_H
#include <crucible/error.h> #include <crucible/error.h>
#include <crucible/process.h>
#include <cassert> #include <cassert>
#include <condition_variable> #include <condition_variable>
#include <iostream> #include <iostream>
#include <limits> #include <limits>
#include <map>
#include <memory>
#include <mutex> #include <mutex>
#include <set>
namespace crucible { namespace crucible {
using namespace std; using namespace std;
@ -18,7 +20,7 @@ namespace crucible {
class LockSet { class LockSet {
public: public:
using set_type = set<T>; using set_type = map<T, pid_t>;
using key_type = typename set_type::key_type; using key_type = typename set_type::key_type;
private: private:
@ -31,6 +33,24 @@ namespace crucible {
bool full(); bool full();
bool locked(const key_type &name); bool locked(const key_type &name);
class Lock {
LockSet &m_lockset;
key_type m_name;
bool m_locked;
Lock() = delete;
Lock(const Lock &) = delete;
Lock& operator=(const Lock &) = delete;
Lock(Lock &&that) = delete;
Lock& operator=(Lock &&that) = delete;
public:
~Lock();
Lock(LockSet &lockset, const key_type &name, bool start_locked = true);
void lock();
void unlock();
bool try_lock();
};
public: public:
~LockSet(); ~LockSet();
LockSet() = default; LockSet() = default;
@ -45,24 +65,18 @@ namespace crucible {
void max_size(size_t max); void max_size(size_t max);
class Lock { class LockHandle {
LockSet &m_lockset; shared_ptr<Lock> m_lock;
key_type m_name;
bool m_locked;
Lock() = delete;
Lock(const Lock &) = delete;
Lock& operator=(const Lock &) = delete;
public: public:
~Lock(); LockHandle(LockSet &lockset, const key_type &name, bool start_locked = true) :
Lock(LockSet &lockset, const key_type &m_name, bool start_locked = true); m_lock(make_shared<Lock>(lockset, name, start_locked)) {}
Lock(Lock &&that); void lock() { m_lock->lock(); }
Lock& operator=(Lock &&that); void unlock() { m_lock->unlock(); }
void lock(); bool try_lock() { return m_lock->try_lock(); }
void unlock();
bool try_lock();
}; };
LockHandle make_lock(const key_type &name, bool start_locked = true);
}; };
template <class T> template <class T>
@ -104,7 +118,7 @@ namespace crucible {
while (full() || locked(name)) { while (full() || locked(name)) {
m_condvar.wait(lock); m_condvar.wait(lock);
} }
auto rv = m_set.insert(name); auto rv = m_set.insert(make_pair(name, gettid()));
THROW_CHECK0(runtime_error, rv.second); THROW_CHECK0(runtime_error, rv.second);
} }
@ -116,7 +130,7 @@ namespace crucible {
if (full() || locked(name)) { if (full() || locked(name)) {
return false; return false;
} }
auto rv = m_set.insert(name); auto rv = m_set.insert(make_pair(name, gettid()));
THROW_CHECK1(runtime_error, name, rv.second); THROW_CHECK1(runtime_error, name, rv.second);
return true; return true;
} }
@ -214,26 +228,10 @@ namespace crucible {
} }
template <class T> template <class T>
LockSet<T>::Lock::Lock(Lock &&that) : typename LockSet<T>::LockHandle
m_lockset(that.lockset), LockSet<T>::make_lock(const key_type &name, bool start_locked)
m_name(that.m_name),
m_locked(that.m_locked)
{ {
that.m_locked = false; return LockHandle(*this, name, start_locked);
}
template <class T>
typename LockSet<T>::Lock &
LockSet<T>::Lock::operator=(Lock &&that)
{
THROW_CHECK2(invalid_argument, &m_lockset, &that.m_lockset, &m_lockset == &that.m_lockset);
if (m_locked && that.m_name != m_name) {
unlock();
}
m_name = that.m_name;
m_locked = that.m_locked;
that.m_locked = false;
return *this;
} }
} }