6 #include "include/types.h"
10 #include <ext/hash_map>
15 #define dout(l) if (l<=g_conf.debug_lockdep) *_dout << g_clock.now() << " " << pthread_self() << " lockdep: "
18 pthread_mutex_t lockdep_mutex = PTHREAD_MUTEX_INITIALIZER;
21 #define MAX_LOCKS 100 // increase me as needed
23 hash_map<const char *, int> lock_ids;
24 map<int, const char *> lock_names;
28 hash_map<pthread_t, map<int,BackTrace*> > held;
29 BackTrace *follows[MAX_LOCKS][MAX_LOCKS]; // follows[a][b] means b taken after a
32 #define BACKTRACE_SKIP 3
35 int lockdep_register(const char *name)
39 pthread_mutex_lock(&lockdep_mutex);
42 for (int i=0; i<MAX_LOCKS; i++)
43 for (int j=0; j<MAX_LOCKS; j++)
46 hash_map<const char *, int>::iterator p = lock_ids.find(name);
47 if (p == lock_ids.end()) {
48 assert(last_id < MAX_LOCKS);
51 lock_names[id] = name;
52 dout(10) << "registered '" << name << "' as " << id << std::endl;
55 dout(20) << "had '" << name << "' as " << id << std::endl;
58 pthread_mutex_unlock(&lockdep_mutex);
65 static bool does_follow(int a, int b)
69 dout(0) << "------------------------------------" << std::endl;
70 dout(0) << "existing dependency " << lock_names[a] << " (" << a << ") -> " << lock_names[b] << " (" << b << ") at: " << std::endl;
71 follows[a][b]->print(*_dout);
76 for (int i=0; i<MAX_LOCKS; i++) {
79 dout(0) << "existing intermediate dependency " << lock_names[a] << " (" << a << ") -> " << lock_names[i] << " (" << i << ") at:" << std::endl;
80 follows[a][i]->print(*_dout);
89 int lockdep_will_lock(const char *name, int id)
91 pthread_t p = pthread_self();
92 if (id < 0) id = lockdep_register(name);
94 pthread_mutex_lock(&lockdep_mutex);
95 dout(20) << "_will_lock " << name << " (" << id << ")" << std::endl;
97 // check dependency graph
98 map<int, BackTrace *> &m = held[p];
99 for (map<int, BackTrace *>::iterator p = m.begin();
102 if (p->first == id) {
104 dout(0) << "recursive lock of " << name << " (" << id << ")" << std::endl;
105 BackTrace *bt = new BackTrace(BACKTRACE_SKIP);
107 if (g_lockdep >= 2) {
109 dout(0) << "previously locked at" << std::endl;
110 p->second->print(*_dout);
115 else if (!follows[p->first][id]) {
118 // did we just create a cycle?
119 BackTrace *bt = new BackTrace(BACKTRACE_SKIP);
120 if (does_follow(id, p->first)) {
121 dout(0) << "new dependency " << lock_names[p->first] << " (" << p->first << ") -> " << name << " (" << id << ")"
122 << " creates a cycle at"
127 dout(0) << "btw, i am holding these locks:" << std::endl;
128 for (map<int, BackTrace *>::iterator q = m.begin();
131 dout(0) << " " << lock_names[q->first] << " (" << q->first << ")" << std::endl;
132 if (g_lockdep >= 2) {
133 q->second->print(*_dout);
141 // don't add this dependency, or we'll get aMutex. cycle in the graph, and
142 // does_follow() won't terminate.
144 assert(0); // actually, we should just die here.
146 follows[p->first][id] = bt;
147 dout(10) << lock_names[p->first] << " -> " << name << " at" << std::endl;
153 pthread_mutex_unlock(&lockdep_mutex);
157 int lockdep_locked(const char *name, int id)
159 pthread_t p = pthread_self();
161 if (id < 0) id = lockdep_register(name);
163 pthread_mutex_lock(&lockdep_mutex);
164 dout(20) << "_locked " << name << std::endl;
166 held[p][id] = new BackTrace(BACKTRACE_SKIP);
169 pthread_mutex_unlock(&lockdep_mutex);
173 int lockdep_unlocked(const char *name, int id)
175 pthread_t p = pthread_self();
177 if (id < 0) id = lockdep_register(name);
179 pthread_mutex_lock(&lockdep_mutex);
180 dout(20) << "_unlocked " << name << std::endl;
182 // don't assert.. lockdep may be enabled at any point in time
183 //assert(held.count(p));
184 //assert(held[p].count(id));
188 pthread_mutex_unlock(&lockdep_mutex);