21 using std::ostringstream;
23 int MutexDebug::_pstats_count = 0;
30 MutexDebug(
const std::string &name,
bool allow_recursion,
bool lightweight) :
32 _allow_recursion(allow_recursion),
33 _lightweight(lightweight),
34 _locking_thread(nullptr),
36 _deleted_name(nullptr),
37 _cvar_impl(*get_global_lock())
39 #ifndef SIMPLE_THREADS 51 nassertv(_locking_thread ==
nullptr && _lock_count == 0);
56 if (name_deleted_mutexes) {
59 std::string name = strm.str();
60 _deleted_name = strdup((
char *)name.c_str());
73 output(ostream &out)
const {
77 if (_allow_recursion) {
78 out <<
"ReMutex " << get_name() <<
" " << (
void *)
this;
80 out <<
"Mutex " << get_name() <<
" " << (
void *)
this;
89 output_with_holder(ostream &out)
const {
92 if (_locking_thread !=
nullptr) {
93 out <<
" (held by " << *_locking_thread <<
")\n";
95 _global_lock->unlock();
105 _global_lock->lock();
107 _global_lock->unlock();
116 _global_lock->lock();
118 _global_lock->unlock();
125 do_lock(
Thread *current_thread) {
128 nassertd(_lock_count != -100) {
130 <<
"Destructed mutex: " << (
void *)
this <<
"\n";
131 if (name_deleted_mutexes && _deleted_name !=
nullptr) {
133 << _deleted_name <<
"\n";
136 <<
"Configure name-deleted-mutexes 1 to see the mutex name.\n";
141 if (_locking_thread ==
nullptr) {
143 _locking_thread = current_thread;
145 nassertv(_lock_count == 1);
147 }
else if (_locking_thread == current_thread) {
149 nassertv(_lock_count > 0);
150 if (!_allow_recursion) {
152 ostr << *current_thread <<
" attempted to double-lock non-reentrant " 154 nassert_raise(ostr.str());
161 if (_lightweight && _pstats_count == 0) {
163 MissedThreads::iterator mi = _missed_threads.insert(MissedThreads::value_type(current_thread, 0)).first;
164 if ((*mi).second == 0) {
166 ostr << *current_thread <<
" not stopped by " << *
this <<
" (held by " 167 << *_locking_thread <<
")\n";
168 nassert_raise(ostr.str());
170 if (!_allow_recursion) {
172 ostr << *current_thread <<
" attempted to double-lock non-reentrant " 174 nassert_raise(ostr.str());
183 MutexDebug *next_mutex =
this;
184 while (next_mutex !=
nullptr) {
185 if (next_mutex->_locking_thread == current_thread) {
187 report_deadlock(current_thread);
188 nassert_raise(
"Deadlock");
191 Thread *next_thread = next_mutex->_locking_thread;
192 if (next_thread ==
nullptr) {
201 next_mutex = next_thread->_blocked_on_mutex;
205 current_thread->_blocked_on_mutex =
this;
209 if (thread_cat->is_debug()) {
211 << *current_thread <<
" blocking on " << *
this <<
" (held by " 212 << *_locking_thread <<
")\n";
215 while (_locking_thread !=
nullptr) {
217 << *current_thread <<
" still blocking on " << *
this <<
" (held by " 218 << *_locking_thread <<
")\n";
222 if (thread_cat.is_debug()) {
224 << *current_thread <<
" acquired " << *
this <<
"\n";
227 current_thread->_blocked_on_mutex =
nullptr;
229 _locking_thread = current_thread;
231 nassertv(_lock_count == 1);
241 do_try_lock(
Thread *current_thread) {
244 nassertd(_lock_count != -100) {
246 <<
"Destructed mutex: " << (
void *)
this <<
"\n";
247 if (name_deleted_mutexes && _deleted_name !=
nullptr) {
249 << _deleted_name <<
"\n";
252 <<
"Configure name-deleted-mutexes 1 to see the mutex name.\n";
257 bool acquired =
true;
258 if (_locking_thread ==
nullptr) {
260 _locking_thread = current_thread;
262 nassertr(_lock_count == 1,
false);
264 }
else if (_locking_thread == current_thread) {
266 nassertr(_lock_count > 0,
false);
267 if (!_allow_recursion) {
277 if (_lightweight && _pstats_count == 0) {
279 MissedThreads::iterator mi = _missed_threads.insert(MissedThreads::value_type(current_thread, 0)).first;
280 if ((*mi).second == 0) {
282 << *current_thread <<
" not stopped by " << *
this <<
" (held by " 283 << *_locking_thread <<
")\n";
285 if (!_allow_recursion) {
287 ostr << *current_thread <<
" attempted to double-lock non-reentrant " 289 nassert_raise(ostr.str());
310 nassertd(_lock_count != -100) {
312 <<
"Destructed mutex: " << (
void *)
this <<
"\n";
313 if (name_deleted_mutexes && _deleted_name !=
nullptr) {
315 << _deleted_name <<
"\n";
318 <<
"Configure name-deleted-mutexes 1 to see the mutex name.\n";
325 if (_locking_thread != current_thread) {
332 MissedThreads::iterator mi = _missed_threads.find(current_thread);
333 nassertv(mi != _missed_threads.end());
334 nassertv((*mi).second > 0);
337 if ((*mi).second == 0) {
338 _missed_threads.erase(mi);
344 ostr << *current_thread <<
" attempted to release " 345 << *
this <<
" which it does not own";
346 nassert_raise(ostr.str());
351 nassertv(_lock_count > 0);
354 if (_lock_count == 0) {
356 _locking_thread =
nullptr;
359 if (!_missed_threads.empty()) {
361 MissedThreads::iterator mi = _missed_threads.begin();
362 _locking_thread = (*mi).first;
363 _lock_count = (*mi).second;
364 _missed_threads.erase(mi);
365 nassertv(_lock_count > 0);
385 do_debug_is_locked()
const {
387 if (_locking_thread == current_thread) {
392 MissedThreads::const_iterator mi = _missed_threads.find(current_thread);
393 if (mi != _missed_threads.end()) {
394 nassertr((*mi).second > 0,
false);
406 report_deadlock(
Thread *current_thread) {
409 <<
"****************************************************************\n" 410 <<
"***** Deadlock detected! *****\n" 411 <<
"****************************************************************\n" 415 << *current_thread <<
" attempted to lock " << *
this 416 <<
" which is held by " << *_locking_thread <<
"\n";
418 MutexDebug *next_mutex =
this;
419 Thread *next_thread = next_mutex->_locking_thread;
420 next_mutex = next_thread->_blocked_on_mutex;
421 while (next_mutex !=
nullptr) {
423 << *next_thread <<
" is blocked waiting on " 424 << *next_mutex <<
" which is held by " 425 << *next_mutex->_locking_thread <<
"\n";
426 next_thread = next_mutex->_locking_thread;
427 next_mutex = next_thread->_blocked_on_mutex;
434 #endif // DEBUG_THREADS PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_current_thread
Returns a pointer to the currently-executing Thread object.
A base class for all things which can have a name.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A thread; that is, a lightweight process.
A fake mutex implementation for single-threaded applications that don't need any synchronization cont...