15 #include "mutexDebug.h" 17 #include "config_pipeline.h" 21 int MutexDebug::_pstats_count = 0;
30 MutexDebug(
const string &name,
bool allow_recursion,
bool lightweight) :
32 _allow_recursion(allow_recursion),
33 _lightweight(lightweight),
34 _locking_thread(NULL),
37 _cvar_impl(*get_global_lock())
39 #ifndef SIMPLE_THREADS 53 nassertv(_locking_thread == NULL && _lock_count == 0);
58 if (name_deleted_mutexes) {
61 string name = strm.str();
62 _deleted_name = strdup((
char *)name.c_str());
77 output(ostream &out)
const {
81 if (_allow_recursion) {
82 out <<
"ReMutex " << get_name() <<
" " << (
void *)
this;
84 out <<
"Mutex " << get_name() <<
" " << (
void *)
this;
95 output_with_holder(ostream &out)
const {
96 _global_lock->acquire();
98 if (_locking_thread != (
Thread *)NULL) {
99 out <<
" (held by " << *_locking_thread <<
")\n";
101 _global_lock->release();
115 _global_lock->acquire();
117 _global_lock->release();
129 _global_lock->acquire();
131 _global_lock->release();
141 do_acquire(
Thread *current_thread) {
144 nassertd(_lock_count != -100) {
146 <<
"Destructed mutex: " << (
void *)
this <<
"\n";
147 if (name_deleted_mutexes && _deleted_name != NULL) {
149 << _deleted_name <<
"\n";
152 <<
"Configure name-deleted-mutexes 1 to see the mutex name.\n";
157 if (_locking_thread == (
Thread *)NULL) {
159 _locking_thread = current_thread;
161 nassertv(_lock_count == 1);
163 }
else if (_locking_thread == current_thread) {
166 nassertv(_lock_count > 0);
167 if (!_allow_recursion) {
169 ostr << *current_thread <<
" attempted to double-lock non-reentrant " 171 nassert_raise(ostr.str());
178 if (_lightweight && _pstats_count == 0) {
180 MissedThreads::iterator mi = _missed_threads.insert(MissedThreads::value_type(current_thread, 0)).first;
181 if ((*mi).second == 0) {
183 ostr << *current_thread <<
" not stopped by " << *
this <<
" (held by " 184 << *_locking_thread <<
")\n";
185 nassert_raise(ostr.str());
187 if (!_allow_recursion) {
189 ostr << *current_thread <<
" attempted to double-lock non-reentrant " 191 nassert_raise(ostr.str());
200 MutexDebug *next_mutex =
this;
201 while (next_mutex != NULL) {
202 if (next_mutex->_locking_thread == current_thread) {
204 report_deadlock(current_thread);
205 nassert_raise(
"Deadlock");
208 Thread *next_thread = next_mutex->_locking_thread;
209 if (next_thread == NULL) {
218 next_mutex = next_thread->_blocked_on_mutex;
222 current_thread->_blocked_on_mutex =
this;
226 if (thread_cat->is_debug()) {
228 << *current_thread <<
" blocking on " << *
this <<
" (held by " 229 << *_locking_thread <<
")\n";
232 while (_locking_thread != (
Thread *)NULL) {
234 << *current_thread <<
" still blocking on " << *
this <<
" (held by " 235 << *_locking_thread <<
")\n";
239 if (thread_cat.is_debug()) {
241 << *current_thread <<
" acquired " << *
this <<
"\n";
244 current_thread->_blocked_on_mutex = NULL;
246 _locking_thread = current_thread;
248 nassertv(_lock_count == 1);
260 do_try_acquire(
Thread *current_thread) {
263 nassertd(_lock_count != -100) {
265 <<
"Destructed mutex: " << (
void *)
this <<
"\n";
266 if (name_deleted_mutexes && _deleted_name != NULL) {
268 << _deleted_name <<
"\n";
271 <<
"Configure name-deleted-mutexes 1 to see the mutex name.\n";
276 bool acquired =
true;
277 if (_locking_thread == (
Thread *)NULL) {
279 _locking_thread = current_thread;
281 nassertr(_lock_count == 1,
false);
283 }
else if (_locking_thread == current_thread) {
286 nassertr(_lock_count > 0,
false);
287 if (!_allow_recursion) {
297 if (_lightweight && _pstats_count == 0) {
299 MissedThreads::iterator mi = _missed_threads.insert(MissedThreads::value_type(current_thread, 0)).first;
300 if ((*mi).second == 0) {
302 << *current_thread <<
" not stopped by " << *
this <<
" (held by " 303 << *_locking_thread <<
")\n";
305 if (!_allow_recursion) {
307 ostr << *current_thread <<
" attempted to double-lock non-reentrant " 309 nassert_raise(ostr.str());
333 nassertd(_lock_count != -100) {
335 <<
"Destructed mutex: " << (
void *)
this <<
"\n";
336 if (name_deleted_mutexes && _deleted_name != NULL) {
338 << _deleted_name <<
"\n";
341 <<
"Configure name-deleted-mutexes 1 to see the mutex name.\n";
348 if (_locking_thread != current_thread) {
355 MissedThreads::iterator mi = _missed_threads.find(current_thread);
356 nassertv(mi != _missed_threads.end());
357 nassertv((*mi).second > 0);
360 if ((*mi).second == 0) {
361 _missed_threads.erase(mi);
367 ostr << *current_thread <<
" attempted to release " 368 << *
this <<
" which it does not own";
369 nassert_raise(ostr.str());
374 nassertv(_lock_count > 0);
377 if (_lock_count == 0) {
379 _locking_thread = (
Thread *)NULL;
382 if (!_missed_threads.empty()) {
384 MissedThreads::iterator mi = _missed_threads.begin();
385 _locking_thread = (*mi).first;
386 _lock_count = (*mi).second;
387 _missed_threads.erase(mi);
388 nassertv(_lock_count > 0);
410 do_debug_is_locked()
const {
412 if (_locking_thread == current_thread) {
417 MissedThreads::const_iterator mi = _missed_threads.find(current_thread);
418 if (mi != _missed_threads.end()) {
419 nassertr((*mi).second > 0,
false);
434 report_deadlock(
Thread *current_thread) {
437 <<
"****************************************************************\n" 438 <<
"***** Deadlock detected! *****\n" 439 <<
"****************************************************************\n" 443 << *current_thread <<
" attempted to lock " << *
this 444 <<
" which is held by " << *_locking_thread <<
"\n";
446 MutexDebug *next_mutex =
this;
447 Thread *next_thread = next_mutex->_locking_thread;
448 next_mutex = next_thread->_blocked_on_mutex;
449 while (next_mutex != NULL) {
451 << *next_thread <<
" is blocked waiting on " 452 << *next_mutex <<
" which is held by " 453 << *next_mutex->_locking_thread <<
"\n";
454 next_thread = next_mutex->_locking_thread;
455 next_mutex = next_thread->_blocked_on_mutex;
462 #endif // DEBUG_THREADS
static Thread * get_current_thread()
Returns a pointer to the currently-executing Thread object.
A base class for all things which can have a name.
A thread; that is, a lightweight process.
A fake mutex implementation for single-threaded applications that don't need any synchronization cont...