#include "common/perf_counters.h"
#include "common/ceph_context.h"
#include "common/config.h"
+#include "include/stringify.h"
#include "include/utime.h"
#include "common/Clock.h"
-Mutex::Mutex(const char *n, bool r, bool ld,
+Mutex::Mutex(const std::string &n, bool r, bool ld,
bool bt,
CephContext *cct) :
- name(n), id(-1), recursive(r), lockdep(ld), backtrace(bt),
- nlock(0), locked_by(0), cct(cct), logger(0)
+ name(n), id(-1), recursive(r), lockdep(ld), backtrace(bt), nlock(0),
+ locked_by(0), cct(cct), logger(0)
{
if (cct) {
PerfCountersBuilder b(cct, string("mutex-") + name,
cct->get_perfcounters_collection()->remove(logger);
delete logger;
}
+ if (g_lockdep) {
+ lockdep_unregister(id);
+ }
}
void Mutex::Lock(bool no_lockdep) {
class Mutex {
private:
- const char *name;
+ std::string name;
int id;
bool recursive;
bool lockdep;
Mutex(const Mutex &M);
void _register() {
- id = lockdep_register(name);
+ id = lockdep_register(name.c_str());
}
void _will_lock() { // about to lock
- id = lockdep_will_lock(name, id);
+ id = lockdep_will_lock(name.c_str(), id);
}
void _locked() { // just locked
- id = lockdep_locked(name, id, backtrace);
+ id = lockdep_locked(name.c_str(), id, backtrace);
}
void _will_unlock() { // about to unlock
- id = lockdep_will_unlock(name, id);
+ id = lockdep_will_unlock(name.c_str(), id);
}
public:
- Mutex(const char *n, bool r = false, bool ld=true, bool bt=false,
+ Mutex(const std::string &n, bool r = false, bool ld=true, bool bt=false,
CephContext *cct = 0);
~Mutex();
bool is_locked() const {
#define CEPH_RWLock_Posix__H
#include <pthread.h>
+#include <string>
#include <include/assert.h>
#include "lockdep.h"
#include "include/atomic.h"
class RWLock
{
mutable pthread_rwlock_t L;
- const char *name;
+ std::string name;
mutable int id;
mutable atomic_t nrlock, nwlock;
+ std::string unique_name(const char* name) const;
+
public:
RWLock(const RWLock& other);
const RWLock& operator=(const RWLock& other);
- RWLock(const char *n) : name(n), id(-1), nrlock(0), nwlock(0) {
+ RWLock(const std::string &n) : name(n), id(-1), nrlock(0), nwlock(0) {
pthread_rwlock_init(&L, NULL);
- if (g_lockdep) id = lockdep_register(name);
+ if (g_lockdep) id = lockdep_register(name.c_str());
}
bool is_locked() const {
// the object and we assume that there are no other users.
assert(!is_locked());
pthread_rwlock_destroy(&L);
+ if (g_lockdep) {
+ lockdep_unregister(id);
+ }
}
void unlock(bool lockdep=true) const {
assert(nrlock.read() > 0);
nrlock.dec();
}
- if (lockdep && g_lockdep) id = lockdep_will_unlock(name, id);
+ if (lockdep && g_lockdep) id = lockdep_will_unlock(name.c_str(), id);
int r = pthread_rwlock_unlock(&L);
assert(r == 0);
}
// read
void get_read() const {
- if (g_lockdep) id = lockdep_will_lock(name, id);
+ if (g_lockdep) id = lockdep_will_lock(name.c_str(), id);
int r = pthread_rwlock_rdlock(&L);
assert(r == 0);
- if (g_lockdep) id = lockdep_locked(name, id);
+ if (g_lockdep) id = lockdep_locked(name.c_str(), id);
nrlock.inc();
}
bool try_get_read() const {
if (pthread_rwlock_tryrdlock(&L) == 0) {
nrlock.inc();
- if (g_lockdep) id = lockdep_locked(name, id);
+ if (g_lockdep) id = lockdep_locked(name.c_str(), id);
return true;
}
return false;
// write
void get_write(bool lockdep=true) {
- if (lockdep && g_lockdep) id = lockdep_will_lock(name, id);
+ if (lockdep && g_lockdep) id = lockdep_will_lock(name.c_str(), id);
int r = pthread_rwlock_wrlock(&L);
assert(r == 0);
- if (g_lockdep) id = lockdep_locked(name, id);
+ if (g_lockdep) id = lockdep_locked(name.c_str(), id);
nwlock.inc();
}
bool try_get_write(bool lockdep=true) {
if (pthread_rwlock_trywrlock(&L) == 0) {
- if (lockdep && g_lockdep) id = lockdep_locked(name, id);
+ if (lockdep && g_lockdep) id = lockdep_locked(name.c_str(), id);
nwlock.inc();
return true;
}
static pthread_mutex_t lockdep_mutex = PTHREAD_MUTEX_INITIALIZER;
static CephContext *g_lockdep_ceph_ctx = NULL;
static lockdep_stopper_t lockdep_stopper;
-static ceph::unordered_map<const char *, int> lock_ids;
-static map<int, const char *> lock_names;
-static int last_id = 0;
+static ceph::unordered_map<std::string, int> lock_ids;
+static map<int, std::string> lock_names;
+static map<int, int> lock_refs;
+static list<int> free_ids;
static ceph::unordered_map<pthread_t, map<int,BackTrace*> > held;
static BackTrace *follows[MAX_LOCKS][MAX_LOCKS]; // follows[a][b] means b taken after a
if (g_lockdep_ceph_ctx == NULL) {
g_lockdep_ceph_ctx = cct;
lockdep_dout(0) << "lockdep start" << dendl;
+
+ for (int i=0; i<MAX_LOCKS; ++i) {
+ free_ids.push_back(i);
+ }
}
pthread_mutex_unlock(&lockdep_mutex);
}
follows[i][j] = NULL;
lock_names.clear();
lock_ids.clear();
- last_id = 0;
+ lock_refs.clear();
+ free_ids.clear();
}
pthread_mutex_unlock(&lockdep_mutex);
}
int id;
pthread_mutex_lock(&lockdep_mutex);
- if (last_id == 0)
- for (int i=0; i<MAX_LOCKS; i++)
- for (int j=0; j<MAX_LOCKS; j++)
- follows[i][j] = NULL;
-
- ceph::unordered_map<const char *, int>::iterator p = lock_ids.find(name);
+ ceph::unordered_map<std::string, int>::iterator p = lock_ids.find(name);
if (p == lock_ids.end()) {
- assert(last_id < MAX_LOCKS);
- id = last_id++;
+ assert(!free_ids.empty());
+ id = free_ids.front();
+ free_ids.pop_front();
+
lock_ids[name] = id;
lock_names[id] = name;
lockdep_dout(10) << "registered '" << name << "' as " << id << dendl;
lockdep_dout(20) << "had '" << name << "' as " << id << dendl;
}
+ ++lock_refs[id];
pthread_mutex_unlock(&lockdep_mutex);
return id;
}
+void lockdep_unregister(int id)
+{
+ if (id < 0) {
+ return;
+ }
+
+ pthread_mutex_lock(&lockdep_mutex);
+
+ map<int, std::string>::iterator p = lock_names.find(id);
+ assert(p != lock_names.end());
+
+ int &refs = lock_refs[id];
+ if (--refs == 0) {
+ // reset dependency ordering
+ for (int i=0; i<MAX_LOCKS; ++i) {
+ delete follows[id][i];
+ follows[id][i] = NULL;
+
+ delete follows[i][id];
+ follows[i][id] = NULL;
+ }
+
+ lockdep_dout(10) << "unregistered '" << p->second << "' from " << id
+ << dendl;
+ lock_ids.erase(p->second);
+ lock_names.erase(id);
+ lock_refs.erase(id);
+ free_ids.push_back(id);
+ } else {
+ lockdep_dout(20) << "have " << refs << " of '" << p->second << "' "
+ << "from " << id << dendl;
+ }
+ pthread_mutex_unlock(&lockdep_mutex);
+}
+
// does b follow a?
static bool does_follow(int a, int b)
extern void lockdep_register_ceph_context(CephContext *cct);
extern void lockdep_unregister_ceph_context(CephContext *cct);
extern int lockdep_register(const char *n);
+extern void lockdep_unregister(int id);
extern int lockdep_will_lock(const char *n, int id);
extern int lockdep_locked(const char *n, int id, bool force_backtrace=false);
extern int lockdep_will_unlock(const char *n, int id);