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:
parent
3901962379
commit
4f66d1cb44
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user