17 #include <glog/logging.h> 23 #include <unordered_map> 24 #include <unordered_set> 34 #ifdef DEBUG_DEADLOCKS 39 std::mutex global_mutex_;
40 std::unordered_map<std::thread::id, const Waitable*> waiting_threads_;
41 std::unordered_map<std::thread::id, const Thread*> all_threads_;
44 std::string ThreadName(std::thread::id
id) {
46 if (all_threads_.count(
id) > 0)
47 ss << all_threads_.at(
id)->name() <<
" (" <<
id <<
")";
57 void DetectDeadlock(
const Waitable* start, std::thread::id start_thread_id) {
58 std::stringstream trace;
59 std::unordered_set<std::thread::id> seen;
60 seen.insert(start_thread_id);
64 std::thread::id prev_thread_id = start_thread_id;
65 const Waitable* waiting_on = start;
68 const std::thread::id provider = waiting_on->GetProvider();
69 if (provider == std::thread::id())
74 if (provider == prev_thread_id)
78 trace <<
"(" << i <<
") " << ThreadName(prev_thread_id) <<
" -> \"" 79 << waiting_on->name() <<
"\" provided by" 80 <<
": (" << (provider == start_thread_id ? 0 : i + 1) <<
")\n";
82 if (seen.count(provider)) {
84 <<
"Deadlock detected:\n" 85 <<
"(i) thread name (id) -> waiting on\n" 86 <<
"--------------------------------------------------------------\n" 88 <<
"--------------------------------------------------------------";
91 if (waiting_threads_.count(provider) == 0)
93 seen.insert(provider);
94 prev_thread_id = provider;
95 waiting_on = waiting_threads_.at(provider);
102 WaitingTracker::TrackerScope::TrackerScope() : exec_(true) {}
104 WaitingTracker::TrackerScope::TrackerScope(TrackerScope&& other) : exec_(true) {
108 WaitingTracker::TrackerScope& WaitingTracker::TrackerScope::operator=(
109 TrackerScope&& other) {
115 WaitingTracker::TrackerScope::~TrackerScope() {
117 std::unique_lock<std::mutex> lock(global_mutex_);
118 CHECK_EQ(waiting_threads_.count(std::this_thread::get_id()), 1u);
119 waiting_threads_.erase(std::this_thread::get_id());
125 void WaitingTracker::AddThread(
const Thread* thread) {
126 std::unique_lock<std::mutex> lock(global_mutex_);
127 CHECK_EQ(all_threads_.count(thread->get_original_id()), 0u);
128 all_threads_[thread->get_original_id()] = thread;
132 void WaitingTracker::RemoveThread(
const Thread* thread) {
133 std::unique_lock<std::mutex> lock(global_mutex_);
134 CHECK_EQ(all_threads_.count(thread->get_original_id()), 1u);
135 CHECK_EQ(waiting_threads_.count(thread->get_original_id()), 0u)
136 <<
"Attempt to destroy thread that is waiting.";
137 all_threads_.erase(thread->get_original_id());
141 void WaitingTracker::RemoveWaitable(
const Waitable* waiting_on) {
142 std::unique_lock<std::mutex> lock(global_mutex_);
143 for (
auto& pair : waiting_threads_) {
144 if (pair.second == waiting_on)
145 LOG(FATAL) <<
"Attempt to destroy an object someone is waiting for.";
150 void WaitingTracker::ThreadExit() {
151 std::unique_lock<std::mutex> lock(global_mutex_);
152 for (
auto& pair : waiting_threads_) {
153 const std::thread::id provider = pair.second->GetProvider();
154 if (provider == std::this_thread::get_id()) {
155 LOG(FATAL) <<
"Waiting on an event whose provider thread has exited: " 156 << pair.second->name();
162 void WaitingTracker::UpdateProvider(
const Waitable* waiting_on) {
163 std::unique_lock<std::mutex> lock(global_mutex_);
165 const std::thread::id provider = waiting_on->GetProvider();
166 if (waiting_threads_.count(provider))
167 DetectDeadlock(waiting_threads_.at(provider), provider);
171 WaitingTracker::TrackerScope WaitingTracker::ThreadWaiting(
173 std::unique_lock<std::mutex> lock(global_mutex_);
175 const std::thread::id this_thread_id = std::this_thread::get_id();
176 DetectDeadlock(waiting_on, this_thread_id);
178 CHECK_EQ(waiting_threads_.count(this_thread_id), 0u)
179 <<
"Somehow waiting on two conditions at once.";
180 waiting_threads_[this_thread_id] = waiting_on;
181 return TrackerScope();
#define END_ALLOW_COMPLEX_STATICS
Waitable(const std::string &name)
#define BEGIN_ALLOW_COMPLEX_STATICS