From 39614e49adbd2f30243c6a12416a3eddaa8bfb23 Mon Sep 17 00:00:00 2001 From: David Rose Date: Fri, 10 Oct 2008 00:08:14 +0000 Subject: [PATCH] fix shutdown order --- panda/src/gobj/vertexDataPage.cxx | 6 ++++- panda/src/gobj/vertexDataPage.h | 2 +- panda/src/pipeline/config_pipeline.cxx | 11 ++++++++ panda/src/pipeline/config_pipeline.h | 1 + panda/src/pipeline/mutexDebug.cxx | 37 ++++++++++++++++++++++++-- panda/src/pipeline/mutexDebug.h | 1 + 6 files changed, 54 insertions(+), 4 deletions(-) diff --git a/panda/src/gobj/vertexDataPage.cxx b/panda/src/gobj/vertexDataPage.cxx index 73db5df16e..47d19f11ce 100644 --- a/panda/src/gobj/vertexDataPage.cxx +++ b/panda/src/gobj/vertexDataPage.cxx @@ -53,7 +53,11 @@ ConfigVariableInt max_disk_vertex_data "limit.")); PT(VertexDataPage::PageThreadManager) VertexDataPage::_thread_mgr; -Mutex VertexDataPage::_tlock; + +// This is a reference to an allocated Mutex, instead of just a static +// Mutex, to protect against ordering issues when the application +// shuts down. +Mutex &VertexDataPage::_tlock = *(new Mutex("VertexDataPage::_tlock")); SimpleLru VertexDataPage::_resident_lru("resident", max_resident_vertex_data); SimpleLru VertexDataPage::_compressed_lru("compressed", max_compressed_vertex_data); diff --git a/panda/src/gobj/vertexDataPage.h b/panda/src/gobj/vertexDataPage.h index 683a852d07..e3bf8ffb0f 100644 --- a/panda/src/gobj/vertexDataPage.h +++ b/panda/src/gobj/vertexDataPage.h @@ -160,7 +160,7 @@ private: }; static PT(PageThreadManager) _thread_mgr; - static Mutex _tlock; // Protects _thread_mgr and all of its members. + static Mutex &_tlock; // Protects _thread_mgr and all of its members. unsigned char *_page_data; size_t _size, _allocated_size, _uncompressed_size; diff --git a/panda/src/pipeline/config_pipeline.cxx b/panda/src/pipeline/config_pipeline.cxx index b0f6912ec7..873d9a5369 100644 --- a/panda/src/pipeline/config_pipeline.cxx +++ b/panda/src/pipeline/config_pipeline.cxx @@ -36,6 +36,17 @@ ConfigVariableBool support_threads "does not affect the operation of mutexes and other synchronization " "primitives, just the creation of threads.")); +ConfigVariableBool name_deleted_mutexes +("name-deleted-mutexes", false, + PRC_DESC("Set this true to allocate a name to each Mutex object that " + "destructs, so if the Mutex is locked after destruction, we can " + "print out its name to aid debugging. This is only available " + "when compiled with DEBUG_THREADS. Enabling this variable will " + "cause a memory leak, so you should only enable it when you are " + "specifically tracking down an operation on a deleted Mutex. " + "It is not guaranteed to work, of course, because the memory " + "for a deleted Mutex may become reused for some other purpose.")); + ConfigVariableInt thread_stack_size ("thread-stack-size", 4194304, PRC_DESC("Specifies the minimum size, in bytes, of the stack that will be " diff --git a/panda/src/pipeline/config_pipeline.h b/panda/src/pipeline/config_pipeline.h index aa9c78479a..128444a78e 100644 --- a/panda/src/pipeline/config_pipeline.h +++ b/panda/src/pipeline/config_pipeline.h @@ -26,6 +26,7 @@ NotifyCategoryDecl(pipeline, EXPCL_PANDA_PIPELINE, EXPTP_PANDA_PIPELINE); NotifyCategoryDecl(thread, EXPCL_PANDA_PIPELINE, EXPTP_PANDA_PIPELINE); extern EXPCL_PANDA_PIPELINE ConfigVariableBool support_threads; +extern ConfigVariableBool name_deleted_mutexes; extern ConfigVariableInt thread_stack_size; extern EXPCL_PANDA_PIPELINE void init_libpipeline(); diff --git a/panda/src/pipeline/mutexDebug.cxx b/panda/src/pipeline/mutexDebug.cxx index f243b8f74e..f9d0509ac2 100755 --- a/panda/src/pipeline/mutexDebug.cxx +++ b/panda/src/pipeline/mutexDebug.cxx @@ -32,6 +32,7 @@ MutexDebug(const string &name, bool allow_recursion, bool lightweight) : _lightweight(lightweight), _locking_thread(NULL), _lock_count(0), + _deleted_name(NULL), _cvar_impl(*get_global_lock()) { #ifndef SIMPLE_THREADS @@ -50,6 +51,16 @@ MutexDebug:: ~MutexDebug() { nassertv(_locking_thread == NULL && _lock_count == 0); + // If the config variable says to, allocate (and leak) a string name + // for the mutex, so we can report which mutex it is that has + // destructed after the fact. + if (name_deleted_mutexes) { + ostringstream strm; + strm << *this; + string name = strm.str(); + _deleted_name = strdup((char *)name.c_str()); + } + // Put a distinctive, bogus lock count in upon destruction, so we'll // be more likely to notice a floating pointer. _lock_count = -100; @@ -83,7 +94,18 @@ void MutexDebug:: do_lock() { // If this assertion is triggered, you tried to lock a // recently-destructed mutex. - nassertv(_lock_count != -100); + nassertd(_lock_count != -100) { + pipeline_cat.error() + << "Destructed mutex: " << (void *)this << "\n"; + if (name_deleted_mutexes && _deleted_name != NULL) { + pipeline_cat.error() + << _deleted_name << "\n"; + } else { + pipeline_cat.error() + << "Configure name-deleted-mutexes 1 to see the mutex name.\n"; + } + return; + } Thread *this_thread = Thread::get_current_thread(); @@ -189,7 +211,18 @@ void MutexDebug:: do_release() { // If this assertion is triggered, you tried to release a // recently-destructed mutex. - nassertv(_lock_count != -100); + nassertd(_lock_count != -100) { + pipeline_cat.error() + << "Destructed mutex: " << (void *)this << "\n"; + if (name_deleted_mutexes && _deleted_name != NULL) { + pipeline_cat.error() + << _deleted_name << "\n"; + } else { + pipeline_cat.error() + << "Configure name-deleted-mutexes 1 to see the mutex name.\n"; + } + return; + } Thread *this_thread = Thread::get_current_thread(); diff --git a/panda/src/pipeline/mutexDebug.h b/panda/src/pipeline/mutexDebug.h index 4dd10f9b2f..d97af57237 100644 --- a/panda/src/pipeline/mutexDebug.h +++ b/panda/src/pipeline/mutexDebug.h @@ -62,6 +62,7 @@ private: bool _lightweight; Thread *_locking_thread; int _lock_count; + char *_deleted_name; // To help I.D. a destructed mutex. // For _lightweight mutexes. typedef pmap MissedThreads;