Fix rare mutex error at shutdown: "MutexPosixImpl::acquire(): Assertion `result == 0' failed."

This commit is contained in:
rdb 2016-05-29 02:03:36 +02:00
parent 7a681dc993
commit b486de2700
2 changed files with 78 additions and 32 deletions

View File

@ -15,9 +15,7 @@
#include "lightMutexHolder.h" #include "lightMutexHolder.h"
#include <algorithm> #include <algorithm>
GraphicsStateGuardianBase::GSGs GraphicsStateGuardianBase::_gsgs; AtomicAdjust::Pointer GraphicsStateGuardianBase::_gsg_list;
GraphicsStateGuardianBase *GraphicsStateGuardianBase::_default_gsg;
LightMutex GraphicsStateGuardianBase::_lock;
TypeHandle GraphicsStateGuardianBase::_type_handle; TypeHandle GraphicsStateGuardianBase::_type_handle;
/** /**
@ -30,8 +28,13 @@ TypeHandle GraphicsStateGuardianBase::_type_handle;
*/ */
GraphicsStateGuardianBase *GraphicsStateGuardianBase:: GraphicsStateGuardianBase *GraphicsStateGuardianBase::
get_default_gsg() { get_default_gsg() {
LightMutexHolder holder(_lock); GSGList *gsg_list = (GSGList *)AtomicAdjust::get_ptr(_gsg_list);
return _default_gsg; if (gsg_list == NULL) {
// Nobody created a GSG list, so we won't have any GSGs either.
return NULL;
}
LightMutexHolder holder(gsg_list->_lock);
return gsg_list->_default_gsg;
} }
/** /**
@ -40,22 +43,35 @@ get_default_gsg() {
*/ */
void GraphicsStateGuardianBase:: void GraphicsStateGuardianBase::
set_default_gsg(GraphicsStateGuardianBase *default_gsg) { set_default_gsg(GraphicsStateGuardianBase *default_gsg) {
LightMutexHolder holder(_lock); GSGList *gsg_list = (GSGList *)AtomicAdjust::get_ptr(_gsg_list);
if (find(_gsgs.begin(), _gsgs.end(), default_gsg) == _gsgs.end()) { if (gsg_list == NULL) {
// Nobody ever created a GSG list. How could we have a GSG?
nassertv(false);
return;
}
LightMutexHolder holder(gsg_list->_lock);
if (find(gsg_list->_gsgs.begin(), gsg_list->_gsgs.end(), default_gsg) == gsg_list->_gsgs.end()) {
// The specified GSG doesn't exist or it has already destructed. // The specified GSG doesn't exist or it has already destructed.
nassertv(false); nassertv(false);
return; return;
} }
_default_gsg = default_gsg; gsg_list->_default_gsg = default_gsg;
} }
/** /**
* Returns the total number of GSG's in the universe. * Returns the total number of GSG's in the universe.
*/ */
int GraphicsStateGuardianBase:: size_t GraphicsStateGuardianBase::
get_num_gsgs() { get_num_gsgs() {
return _gsgs.size(); GSGList *gsg_list = (GSGList *)AtomicAdjust::get_ptr(_gsg_list);
if (gsg_list == NULL) {
// Nobody created a GSG list, so we won't have any GSGs either.
return 0;
}
LightMutexHolder holder(gsg_list->_lock);
return gsg_list->_gsgs.size();
} }
/** /**
@ -63,9 +79,13 @@ get_num_gsgs() {
* and remove themselves from this list as they are created and destroyed. * and remove themselves from this list as they are created and destroyed.
*/ */
GraphicsStateGuardianBase *GraphicsStateGuardianBase:: GraphicsStateGuardianBase *GraphicsStateGuardianBase::
get_gsg(int n) { get_gsg(size_t n) {
nassertr(n >= 0 && n < (int)_gsgs.size(), NULL); GSGList *gsg_list = (GSGList *)AtomicAdjust::get_ptr(_gsg_list);
return _gsgs[n]; nassertr(gsg_list != NULL, NULL);
LightMutexHolder holder(gsg_list->_lock);
nassertr(n < gsg_list->_gsgs.size(), NULL);
return gsg_list->_gsgs[n];
} }
/** /**
@ -74,17 +94,32 @@ get_gsg(int n) {
*/ */
void GraphicsStateGuardianBase:: void GraphicsStateGuardianBase::
add_gsg(GraphicsStateGuardianBase *gsg) { add_gsg(GraphicsStateGuardianBase *gsg) {
LightMutexHolder holder(_lock); GSGList *gsg_list = (GSGList *)AtomicAdjust::get_ptr(_gsg_list);
if (gsg_list == NULL) {
gsg_list = new GSGList;
gsg_list->_default_gsg = NULL;
if (find(_gsgs.begin(), _gsgs.end(), gsg) != _gsgs.end()) { GSGList *orig_gsg_list = (GSGList *)
AtomicAdjust::compare_and_exchange_ptr(_gsg_list, NULL, gsg_list);
if (orig_gsg_list != NULL) {
// Another thread beat us to it. No problem, we'll use that.
delete gsg_list;
gsg_list = orig_gsg_list;
}
}
LightMutexHolder holder(gsg_list->_lock);
if (find(gsg_list->_gsgs.begin(), gsg_list->_gsgs.end(), gsg) != gsg_list->_gsgs.end()) {
// Already on the list. // Already on the list.
return; return;
} }
_gsgs.push_back(gsg); gsg_list->_gsgs.push_back(gsg);
if (_default_gsg == (GraphicsStateGuardianBase *)NULL) { if (gsg_list->_default_gsg == (GraphicsStateGuardianBase *)NULL) {
_default_gsg = gsg; gsg_list->_default_gsg = gsg;
} }
} }
@ -93,21 +128,28 @@ add_gsg(GraphicsStateGuardianBase *gsg) {
*/ */
void GraphicsStateGuardianBase:: void GraphicsStateGuardianBase::
remove_gsg(GraphicsStateGuardianBase *gsg) { remove_gsg(GraphicsStateGuardianBase *gsg) {
LightMutexHolder holder(_lock); GSGList *gsg_list = (GSGList *)AtomicAdjust::get_ptr(_gsg_list);
if (gsg_list == NULL) {
// No GSGs were added yet, or the program is destructing anyway.
return;
}
GSGs::iterator gi = find(_gsgs.begin(), _gsgs.end(), gsg); LightMutexHolder holder(gsg_list->_lock);
if (gi == _gsgs.end()) {
GSGList::GSGs::iterator gi;
gi = find(gsg_list->_gsgs.begin(), gsg_list->_gsgs.end(), gsg);
if (gi == gsg_list->_gsgs.end()) {
// Already removed, or never added. // Already removed, or never added.
return; return;
} }
_gsgs.erase(gi); gsg_list->_gsgs.erase(gi);
if (_default_gsg == gsg) { if (gsg_list->_default_gsg == gsg) {
if (!_gsgs.empty()) { if (!gsg_list->_gsgs.empty()) {
_default_gsg = *_gsgs.begin(); gsg_list->_default_gsg = *gsg_list->_gsgs.begin();
} else { } else {
_default_gsg = NULL; gsg_list->_default_gsg = NULL;
} }
} }
} }

View File

@ -223,8 +223,8 @@ PUBLISHED:
static GraphicsStateGuardianBase *get_default_gsg(); static GraphicsStateGuardianBase *get_default_gsg();
static void set_default_gsg(GraphicsStateGuardianBase *default_gsg); static void set_default_gsg(GraphicsStateGuardianBase *default_gsg);
static int get_num_gsgs(); static size_t get_num_gsgs();
static GraphicsStateGuardianBase *get_gsg(int n); static GraphicsStateGuardianBase *get_gsg(size_t n);
MAKE_SEQ(get_gsgs, get_num_gsgs, get_gsg); MAKE_SEQ(get_gsgs, get_num_gsgs, get_gsg);
public: public:
@ -232,10 +232,14 @@ public:
static void remove_gsg(GraphicsStateGuardianBase *gsg); static void remove_gsg(GraphicsStateGuardianBase *gsg);
private: private:
typedef pvector<GraphicsStateGuardianBase *> GSGs; struct GSGList {
static GSGs _gsgs; LightMutex _lock;
static GraphicsStateGuardianBase *_default_gsg;
static LightMutex _lock; typedef pvector<GraphicsStateGuardianBase *> GSGs;
GSGs _gsgs;
GraphicsStateGuardianBase *_default_gsg;
};
static AtomicAdjust::Pointer _gsg_list;
public: public:
static TypeHandle get_class_type() { static TypeHandle get_class_type() {