Browse Source

thread protection in miles

David Rose 19 years ago
parent
commit
b3c42f22ac

+ 185 - 69
panda/src/audiotraits/milesAudioManager.cxx

@@ -27,12 +27,14 @@
 #include "config_express.h"
 #include "config_express.h"
 #include "virtualFileSystem.h"
 #include "virtualFileSystem.h"
 #include "nullAudioSound.h"
 #include "nullAudioSound.h"
+#include "mutexHolder.h"
 
 
 #include <algorithm>
 #include <algorithm>
 
 
 
 
 TypeHandle MilesAudioManager::_type_handle;
 TypeHandle MilesAudioManager::_type_handle;
 
 
+Mutex *MilesAudioManager::_static_lock;
 int MilesAudioManager::_active_managers = 0;
 int MilesAudioManager::_active_managers = 0;
 bool MilesAudioManager::_miles_active = false;
 bool MilesAudioManager::_miles_active = false;
 HDLSFILEID MilesAudioManager::_dls_field = NULL;
 HDLSFILEID MilesAudioManager::_dls_field = NULL;
@@ -59,6 +61,18 @@ MilesAudioManager::
 MilesAudioManager() {
 MilesAudioManager() {
   audio_debug("MilesAudioManager::MilesAudioManager(), this = " 
   audio_debug("MilesAudioManager::MilesAudioManager(), this = " 
               << (void *)this);
               << (void *)this);
+  if (_static_lock == NULL) {
+    Mutex *new_lock = new Mutex;
+    void *result = AtomicAdjust::compare_and_exchange_ptr((void * TVOLATILE &)_static_lock, (void *)NULL, (void *)new_lock);
+    if (result != NULL) {
+      // Someone else must have assigned the mutex first.  OK.
+      nassertv(_static_lock != new_lock);
+      delete new_lock;
+    }
+    nassertv((Mutex * TVOLATILE &)_static_lock != NULL);
+  }
+
+  MutexHolder st_holder(*(Mutex * TVOLATILE &)_static_lock);
   if (_managers == (Managers *)NULL) {
   if (_managers == (Managers *)NULL) {
     _managers = new Managers;
     _managers = new Managers;
   }
   }
@@ -165,14 +179,22 @@ MilesAudioManager() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 MilesAudioManager::
 MilesAudioManager::
 ~MilesAudioManager() {
 ~MilesAudioManager() {
-  audio_debug("MilesAudioManager::~MilesAudioManager(), this = " 
-              << (void *)this);
-  nassertv(_managers != (Managers *)NULL);
-  Managers::iterator mi = _managers->find(this);
-  nassertv(mi != _managers->end());
-  _managers->erase(mi);
+  {
+    MutexHolder st_holder(*_static_lock);
+    audio_debug("MilesAudioManager::~MilesAudioManager(), this = " 
+                << (void *)this);
+    nassertv(_managers != (Managers *)NULL);
+    Managers::iterator mi = _managers->find(this);
+    if (mi != _managers->end()) {
+      // The manager might already have been removed from the list, if
+      // the user has already called shutdown().
+      nassertv(!_cleanup_required);
+      _managers->erase(mi);
+    }
+  }
 
 
   cleanup();
   cleanup();
+
   audio_debug("MilesAudioManager::~MilesAudioManager() finished");
   audio_debug("MilesAudioManager::~MilesAudioManager() finished");
 }
 }
 
 
@@ -187,27 +209,60 @@ MilesAudioManager::
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void MilesAudioManager::
 void MilesAudioManager::
 shutdown() {
 shutdown() {
-  audio_debug("shutdown(), _miles_active = " << _miles_active);
-  if (_managers != (Managers *)NULL) {
-    Managers::iterator mi;
-    for (mi = _managers->begin(); mi != _managers->end(); ++mi) {
-      (*mi)->cleanup();
+  Managers old_managers;
+  {
+    MutexHolder st_holder(*_static_lock);
+    
+    audio_debug("shutdown(), _miles_active = " << _miles_active);
+    if (_managers != (Managers *)NULL) {
+      old_managers.swap(*_managers);
     }
     }
   }
   }
 
 
+  // We insist on cleaning up our manager pointers, rather than
+  // relying on their destructors, since there might be outstanding
+  // pointers to these somewhere that would otherwise prevent them
+  // from being cleaned up and therefore prevent Miles from being shut
+  // down properly.  In order for this to work, we must write
+  // cleanup() so that it is safe to call it twice.
+  Managers::iterator mi;
+  for (mi = old_managers.begin(); mi != old_managers.end(); ++mi) {
+    (*mi)->cleanup();
+  }
+
+  // Another thread might conceivably have started up a new manager
+  // after we called shutdown(), which is technically legal and would
+  // incorrectly trigger the following assertion.  However, presumably
+  // shutdown() will only be called as the application is shutting
+  // down anyway, and there won't be any other threads still out there
+  // creating audio managers (and if there were, it would defeat the
+  // purpose of shutdown() anyway).
   nassertv(_active_managers == 0);
   nassertv(_active_managers == 0);
+
   audio_debug("shutdown() finished");
   audio_debug("shutdown() finished");
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: MilesAudioManager::is_valid
 //     Function: MilesAudioManager::is_valid
-//       Access:
+//       Access: Public
 //  Description: This is mostly for debugging, but it it could be
 //  Description: This is mostly for debugging, but it it could be
 //               used to detect errors in a release build if you
 //               used to detect errors in a release build if you
 //               don't mind the cpu cost.
 //               don't mind the cpu cost.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool MilesAudioManager::
 bool MilesAudioManager::
 is_valid() {
 is_valid() {
+  MutexHolder holder(_lock);
+
+  return do_is_valid();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioManager::do_is_valid
+//       Access: Private
+//  Description: Assumes the lock is already held.
+////////////////////////////////////////////////////////////////////
+bool MilesAudioManager::
+do_is_valid() {
   bool check=true;
   bool check=true;
   if (_sounds.size() != _lru.size()) {
   if (_sounds.size() != _lru.size()) {
     audio_debug("-- Error _sounds.size() != _lru.size() --");
     audio_debug("-- Error _sounds.size() != _lru.size() --");
@@ -320,59 +375,82 @@ get_sound(const string& file_name, bool) {
      return get_null_sound();
      return get_null_sound();
   }
   }
 
 
-  assert(is_valid());
   Filename path = file_name;
   Filename path = file_name;
 
 
   VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
   VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
   vfs->resolve_filename(path, get_sound_path());
   vfs->resolve_filename(path, get_sound_path());
   audio_debug("  resolved file_name is '"<<path<<"'");
   audio_debug("  resolved file_name is '"<<path<<"'");
 
 
+  const string *cache_path = NULL;
   PT(SoundData) sd;
   PT(SoundData) sd;
+
   // Get the sound, either from the cache or from a loader:
   // Get the sound, either from the cache or from a loader:
-  SoundMap::const_iterator si=_sounds.find(path);
+  MutexHolder holder(_lock);
+
+  assert(do_is_valid());
+
+  SoundMap::const_iterator si = _sounds.find(path);
   if (si != _sounds.end()) {
   if (si != _sounds.end()) {
     // ...found the sound in the cache.
     // ...found the sound in the cache.
+    cache_path = &((*si).first);
     sd = (*si).second;
     sd = (*si).second;
     audio_debug("  sound found in pool 0x" << (void*)sd);
     audio_debug("  sound found in pool 0x" << (void*)sd);
-  } else {
+  }
+
+  if (sd == (SoundData *)NULL) {
     // ...the sound was not found in the cache/pool.
     // ...the sound was not found in the cache/pool.
+    _lock.release();
     sd = load(path);
     sd = load(path);
+    _lock.lock();
+
     if (sd != (SoundData *)NULL) {
     if (sd != (SoundData *)NULL) {
-      while (_sounds.size() >= (unsigned int)_cache_limit) {
-        uncache_a_sound();
-      }
-      // Put it in the pool:
-      // The following is roughly like: _sounds[path] = sd;
-      // But, it gives us an iterator into the map.
-      pair<SoundMap::const_iterator, bool> ib
-          =_sounds.insert(SoundMap::value_type(path, sd));
-      if (!ib.second) {
-        // The insert failed.
-        audio_debug("  failed map insert of "<<path);
-        assert(is_valid());
-        return get_null_sound();
+      SoundMap::const_iterator si = _sounds.find(path);
+      if (si != _sounds.end()) {
+        // Oops, someone else must have just put it in the cache.
+        // Throw away the sound object we just loaded.
+        cache_path = &((*si).first);
+        sd = (*si).second;
+        audio_debug("  sound found in pool 0x" << (void*)sd);
+        
+      } else {
+        // OK, put the sound object we just loaded into the cache.
+        while (_sounds.size() >= (unsigned int)_cache_limit) {
+          uncache_a_sound();
+        }
+
+        // The following is roughly like: _sounds[path] = sd;
+        // But, it gives us an iterator into the map.
+        pair<SoundMap::const_iterator, bool> ib =
+          _sounds.insert(SoundMap::value_type(path, sd));
+        if (!ib.second) {
+          // The insert failed.
+          audio_debug("  failed map insert of "<<path);
+          assert(do_is_valid());
+          return get_null_sound();
+        }
+        // Get a reference to the path for the MilesAudioSound.
+        SoundMap::const_iterator si = ib.first;
+        cache_path = &((*si).first);
       }
       }
-      // Set si, so that we can get a reference to the path
-      // for the MilesAudioSound.
-      si=ib.first;
     }
     }
   }
   }
+
   // Create an AudioSound from the sound:
   // Create an AudioSound from the sound:
-  PT(AudioSound) audioSound = 0;
+  PT(AudioSound) audioSound;
   if (sd != (SoundData *)NULL) {
   if (sd != (SoundData *)NULL) {
-    most_recently_used((*si).first);
-    PT(MilesAudioSound) milesAudioSound
-        =new MilesAudioSound(this, sd, (*si).first);
-    nassertr(milesAudioSound, 0);
+    nassertr(cache_path != NULL, NULL);
+    most_recently_used(cache_path);
+    PT(MilesAudioSound) milesAudioSound = new MilesAudioSound(this, sd, path);
+    nassertr(milesAudioSound, NULL);
     milesAudioSound->set_active(_active);
     milesAudioSound->set_active(_active);
     bool inserted = _sounds_on_loan.insert(milesAudioSound).second;
     bool inserted = _sounds_on_loan.insert(milesAudioSound).second;
     nassertr(inserted, milesAudioSound.p());
     nassertr(inserted, milesAudioSound.p());
-    audioSound=milesAudioSound;
+    audioSound = milesAudioSound;
   }
   }
 
 
   _hasMidiSounds |= (file_name.find(".mid")!=string::npos);
   _hasMidiSounds |= (file_name.find(".mid")!=string::npos);
   audio_debug("  returning 0x" << (void*)audioSound);
   audio_debug("  returning 0x" << (void*)audioSound);
-  assert(is_valid());
+  assert(do_is_valid());
   return audioSound;
   return audioSound;
 }
 }
 
 
@@ -382,17 +460,19 @@ get_sound(const string& file_name, bool) {
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void MilesAudioManager::
 void MilesAudioManager::
-uncache_sound(const string& file_name) {
+uncache_sound(const string &file_name) {
+  MutexHolder holder(_lock);
+
   audio_debug("MilesAudioManager::uncache_sound(file_name=\""
   audio_debug("MilesAudioManager::uncache_sound(file_name=\""
       <<file_name<<"\")");
       <<file_name<<"\")");
-  assert(is_valid());
+  assert(do_is_valid());
   Filename path = file_name;
   Filename path = file_name;
 
 
   VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
   VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
   vfs->resolve_filename(path, get_sound_path());
   vfs->resolve_filename(path, get_sound_path());
 
 
   audio_debug("  path=\""<<path<<"\"");
   audio_debug("  path=\""<<path<<"\"");
-  SoundMap::iterator i=_sounds.find(path);
+  SoundMap::iterator i = _sounds.find(path);
   if (i != _sounds.end()) {
   if (i != _sounds.end()) {
     assert(_lru.size()>0);
     assert(_lru.size()>0);
     LRU::iterator lru_i=find(_lru.begin(), _lru.end(), &(i->first));
     LRU::iterator lru_i=find(_lru.begin(), _lru.end(), &(i->first));
@@ -400,18 +480,18 @@ uncache_sound(const string& file_name) {
     _lru.erase(lru_i);
     _lru.erase(lru_i);
     _sounds.erase(i);
     _sounds.erase(i);
   }
   }
-  assert(is_valid());
+  assert(do_is_valid());
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: MilesAudioManager::uncache_a_sound
 //     Function: MilesAudioManager::uncache_a_sound
-//       Access: Public
-//  Description:
+//       Access: Private
+//  Description: Assumes the lock is already held.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void MilesAudioManager::
 void MilesAudioManager::
 uncache_a_sound() {
 uncache_a_sound() {
   audio_debug("MilesAudioManager::uncache_a_sound()");
   audio_debug("MilesAudioManager::uncache_a_sound()");
-  assert(is_valid());
+  assert(do_is_valid());
   // uncache least recently used:
   // uncache least recently used:
   assert(_lru.size()>0);
   assert(_lru.size()>0);
   LRU::reference path=_lru.front();
   LRU::reference path=_lru.front();
@@ -423,26 +503,26 @@ uncache_a_sound() {
     audio_debug("  uncaching \""<<i->first<<"\"");
     audio_debug("  uncaching \""<<i->first<<"\"");
     _sounds.erase(i);
     _sounds.erase(i);
   }
   }
-  assert(is_valid());
+  assert(do_is_valid());
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: MilesAudioManager::most_recently_used
 //     Function: MilesAudioManager::most_recently_used
-//       Access: Public
-//  Description:
+//       Access: Private
+//  Description: Assumes the lock is already held.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void MilesAudioManager::
 void MilesAudioManager::
-most_recently_used(const string& path) {
+most_recently_used(const string *path) {
   audio_debug("MilesAudioManager::most_recently_used(path=\""
   audio_debug("MilesAudioManager::most_recently_used(path=\""
       <<path<<"\")");
       <<path<<"\")");
-  LRU::iterator i=find(_lru.begin(), _lru.end(), &path);
+  LRU::iterator i=find(_lru.begin(), _lru.end(), path);
   if (i != _lru.end()) {
   if (i != _lru.end()) {
     _lru.erase(i);
     _lru.erase(i);
   }
   }
   // At this point, path should not exist in the _lru:
   // At this point, path should not exist in the _lru:
-  assert(find(_lru.begin(), _lru.end(), &path) == _lru.end());
-  _lru.push_back(&path);
-  assert(is_valid());
+  assert(find(_lru.begin(), _lru.end(), path) == _lru.end());
+  _lru.push_back(path);
+  assert(do_is_valid());
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -452,11 +532,22 @@ most_recently_used(const string& path) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void MilesAudioManager::
 void MilesAudioManager::
 clear_cache() {
 clear_cache() {
+  MutexHolder holder(_lock);
+  do_clear_cache();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioManager::do_clear_cache
+//       Access: Private
+//  Description: Assumes the lock is already held.
+////////////////////////////////////////////////////////////////////
+void MilesAudioManager::
+do_clear_cache() {
   audio_debug("MilesAudioManager::clear_cache()");
   audio_debug("MilesAudioManager::clear_cache()");
-  if (_is_valid) { assert(is_valid()); }
+  if (_is_valid) { assert(do_is_valid()); }
   _sounds.clear();
   _sounds.clear();
   _lru.clear();
   _lru.clear();
-  if (_is_valid) { assert(is_valid()); }
+  if (_is_valid) { assert(do_is_valid()); }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -466,13 +557,15 @@ clear_cache() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void MilesAudioManager::
 void MilesAudioManager::
 set_cache_limit(unsigned int count) {
 set_cache_limit(unsigned int count) {
+  MutexHolder holder(_lock);
+
   audio_debug("MilesAudioManager::set_cache_limit(count="<<count<<")");
   audio_debug("MilesAudioManager::set_cache_limit(count="<<count<<")");
-  assert(is_valid());
+  assert(do_is_valid());
   while (_lru.size() > count) {
   while (_lru.size() > count) {
     uncache_a_sound();
     uncache_a_sound();
   }
   }
   _cache_limit=count;
   _cache_limit=count;
-  assert(is_valid());
+  assert(do_is_valid());
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -482,6 +575,8 @@ set_cache_limit(unsigned int count) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 unsigned int MilesAudioManager::
 unsigned int MilesAudioManager::
 get_cache_limit() const {
 get_cache_limit() const {
+  MutexHolder holder(_lock);
+
   audio_debug("MilesAudioManager::get_cache_limit() returning "
   audio_debug("MilesAudioManager::get_cache_limit() returning "
       <<_cache_limit);
       <<_cache_limit);
   return _cache_limit;
   return _cache_limit;
@@ -494,6 +589,8 @@ get_cache_limit() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void MilesAudioManager::
 void MilesAudioManager::
 release_sound(MilesAudioSound* audioSound) {
 release_sound(MilesAudioSound* audioSound) {
+  MutexHolder holder(_lock);
+
   audio_debug("MilesAudioManager::release_sound(audioSound=\""
   audio_debug("MilesAudioManager::release_sound(audioSound=\""
               <<audioSound->get_name()<<"\"), this = " << (void *)this);
               <<audioSound->get_name()<<"\"), this = " << (void *)this);
   AudioSet::iterator ai = _sounds_on_loan.find(audioSound);
   AudioSet::iterator ai = _sounds_on_loan.find(audioSound);
@@ -766,19 +863,40 @@ force_midi_reset() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void MilesAudioManager::
 void MilesAudioManager::
 cleanup() {
 cleanup() {
-  audio_debug("MilesAudioManager::cleanup(), this = " << (void *)this
-              << ", _cleanup_required = " << _cleanup_required);
-  if (!_cleanup_required) {
-    return;
-  }
+  {
+    MutexHolder holder(_lock);
+    
+    audio_debug("MilesAudioManager::cleanup(), this = " << (void *)this
+                << ", _cleanup_required = " << _cleanup_required);
+    if (!_cleanup_required) {
+      return;
+    }
+    
+    // Be sure to cleanup associated sounds before cleaning up the manager:
+    AudioSet::iterator ai;
+    for (ai = _sounds_on_loan.begin(); ai != _sounds_on_loan.end(); ++ai) {
+      (*ai)->cleanup();
+    }
+
+    do_clear_cache();
 
 
-  // Be sure to cleanup associated sounds before cleaning up the manager:
-  AudioSet::iterator ai;
-  for (ai = _sounds_on_loan.begin(); ai != _sounds_on_loan.end(); ++ai) {
-    (*ai)->cleanup();
+    _cleanup_required = false;
   }
   }
 
 
-  clear_cache();
+  deactivate();
+
+  audio_debug("MilesAudioManager::cleanup() finished");
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MilesAudioManager::deactivate
+//       Access: Private, Static
+//  Description: Deactivates one manager.  Grabs the static lock.
+////////////////////////////////////////////////////////////////////
+void MilesAudioManager::
+deactivate() {
+  MutexHolder st_holder(*_static_lock);
+
   nassertv(_active_managers > 0);
   nassertv(_active_managers > 0);
   --_active_managers;
   --_active_managers;
   audio_debug("  _active_managers="<<_active_managers);
   audio_debug("  _active_managers="<<_active_managers);
@@ -798,8 +916,6 @@ cleanup() {
       _miles_active = false;
       _miles_active = false;
     }
     }
   }
   }
-  _cleanup_required = false;
-  audio_debug("MilesAudioManager::cleanup() finished");
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 22 - 8
panda/src/audiotraits/milesAudioManager.h

@@ -28,6 +28,7 @@
 #include "pset.h"
 #include "pset.h"
 #include "pmap.h"
 #include "pmap.h"
 #include "pdeque.h"
 #include "pdeque.h"
+#include "pmutex.h"
 
 
 class MilesAudioSound;
 class MilesAudioSound;
 
 
@@ -65,6 +66,8 @@ public:
   void stop_all_sounds();
   void stop_all_sounds();
 
 
 private:
 private:
+  Mutex _lock; // Protects all the members of this class.
+
   // The sound cache:
   // The sound cache:
   class SoundData : public ReferenceCount {
   class SoundData : public ReferenceCount {
   public:
   public:
@@ -82,16 +85,16 @@ private:
   typedef pmap<string, PT(SoundData) > SoundMap;
   typedef pmap<string, PT(SoundData) > SoundMap;
   SoundMap _sounds;
   SoundMap _sounds;
 
 
-  typedef pset<MilesAudioSound* > AudioSet;
+  typedef pset<MilesAudioSound *> AudioSet;
   // The offspring of this manager:
   // The offspring of this manager:
   AudioSet _sounds_on_loan;
   AudioSet _sounds_on_loan;
 
 
-  typedef pset<MilesAudioSound* > SoundsPlaying;
+  typedef pset<MilesAudioSound *> SoundsPlaying;
   // The sounds from this manager that are currently playing:
   // The sounds from this manager that are currently playing:
   SoundsPlaying _sounds_playing;
   SoundsPlaying _sounds_playing;
 
 
   // The Least Recently Used mechanism:
   // The Least Recently Used mechanism:
-  typedef pdeque<const string* > LRU;
+  typedef pdeque<const string *> LRU;
   LRU _lru;
   LRU _lru;
   // State:
   // State:
   float _volume;
   float _volume;
@@ -99,25 +102,35 @@ private:
   bool _active;
   bool _active;
   int _cache_limit;
   int _cache_limit;
   bool _cleanup_required;
   bool _cleanup_required;
-  // keep a count for startup and shutdown:
-  static int _active_managers;
-  static bool _miles_active;
+
   unsigned int _concurrent_sound_limit;
   unsigned int _concurrent_sound_limit;
   
   
   bool _is_valid;
   bool _is_valid;
   bool _hasMidiSounds;
   bool _hasMidiSounds;
 
 
+private:
+  // Static members.  Protected by the following lock.
+  static Mutex *_static_lock;
+
+  // keep a count for startup and shutdown:
+  static int _active_managers;
+  static bool _miles_active;
+
   // Optional Downloadable Sound field for software midi
   // Optional Downloadable Sound field for software midi
   static HDLSFILEID _dls_field;
   static HDLSFILEID _dls_field;
 
 
   typedef pset<MilesAudioManager *> Managers;
   typedef pset<MilesAudioManager *> Managers;
   static Managers *_managers;
   static Managers *_managers;
-  
+
+private:  
+  bool do_is_valid();
+  void do_clear_cache();
+
   PT(SoundData) load(Filename file_name);
   PT(SoundData) load(Filename file_name);
   // Tell the manager that the sound dtor was called.
   // Tell the manager that the sound dtor was called.
   void release_sound(MilesAudioSound* audioSound);
   void release_sound(MilesAudioSound* audioSound);
   
   
-  void most_recently_used(const string& path);
+  void most_recently_used(const string *path);
   void uncache_a_sound();
   void uncache_a_sound();
 
 
   void starting_sound(MilesAudioSound* audio);
   void starting_sound(MilesAudioSound* audio);
@@ -133,6 +146,7 @@ private:
 
 
   void force_midi_reset();
   void force_midi_reset();
   void cleanup();
   void cleanup();
+  static void deactivate();
 
 
   friend class MilesAudioSound;
   friend class MilesAudioSound;
 
 

+ 1 - 1
panda/src/audiotraits/milesAudioSound.h

@@ -149,7 +149,7 @@ private:
   // itwas set inactive.
   // itwas set inactive.
   bool _paused;
   bool _paused;
 
 
-  MilesAudioSound(MilesAudioManager* manager, MilesAudioManager::SoundData *sd,
+  MilesAudioSound(MilesAudioManager *manager, MilesAudioManager::SoundData *sd,
                   string file_name, float length=0.0f);
                   string file_name, float length=0.0f);
   void cleanup();
   void cleanup();
 
 

+ 2 - 1
panda/src/event/asyncTaskManager.cxx

@@ -330,7 +330,7 @@ find_task(AsyncTask *task) const {
 void AsyncTaskManager::
 void AsyncTaskManager::
 service_one_task(AsyncTaskManager::AsyncTaskManagerThread *thread) {
 service_one_task(AsyncTaskManager::AsyncTaskManagerThread *thread) {
   if (!_active.empty()) {
   if (!_active.empty()) {
-    AsyncTask *task = _active.front();
+    PT(AsyncTask) task = _active.front();
     _active.pop_front();
     _active.pop_front();
     thread->_servicing = task;
     thread->_servicing = task;
 
 
@@ -375,6 +375,7 @@ void AsyncTaskManager::
 task_done(AsyncTask *task) {
 task_done(AsyncTask *task) {
   task->_state = AsyncTask::S_inactive;
   task->_state = AsyncTask::S_inactive;
   task->_manager = NULL;
   task->_manager = NULL;
+  --_num_tasks;
 
 
   if (!task->_done_event.empty()) {
   if (!task->_done_event.empty()) {
     PT_Event event = new Event(task->_done_event);
     PT_Event event = new Event(task->_done_event);

+ 1 - 1
panda/src/event/config_event.cxx

@@ -40,7 +40,7 @@ ConfigureFn(config_event) {
   EventStoreDouble::init_type("EventStoreDouble");
   EventStoreDouble::init_type("EventStoreDouble");
   EventStoreString::init_type("EventStoreString");
   EventStoreString::init_type("EventStoreString");
   EventStoreWstring::init_type("EventStoreWstring");
   EventStoreWstring::init_type("EventStoreWstring");
-  EventStoreTypedRefCount::init_type("EventStoreTypedRefCount");
+  EventStoreTypedRefCount::init_type();
 
 
   ButtonEventList::register_with_read_factory();
   ButtonEventList::register_with_read_factory();
   EventStoreInt::register_with_read_factory();
   EventStoreInt::register_with_read_factory();

+ 82 - 0
panda/src/event/eventParameter.I

@@ -47,6 +47,24 @@ EventParameter() {
 INLINE EventParameter::
 INLINE EventParameter::
 EventParameter(const TypedWritableReferenceCount *ptr) : _ptr((TypedWritableReferenceCount *)ptr) { }
 EventParameter(const TypedWritableReferenceCount *ptr) : _ptr((TypedWritableReferenceCount *)ptr) { }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: EventParameter::Pointer constructor
+//       Access: Public
+//  Description: Defines an EventParameter that stores a pointer to
+//               a TypedReferenceCount object.  Note that a
+//               TypedReferenceCount is not the same kind of pointer
+//               as a TypedWritableReferenceCount, hence we require
+//               both constructors.
+//
+//               This accepts a const pointer, even though it stores
+//               (and eventually returns) a non-const pointer.  This
+//               is just the simplest way to allow both const and
+//               non-const pointers to be stored, but it does lose the
+//               constness.  Be careful.
+////////////////////////////////////////////////////////////////////
+INLINE EventParameter::
+EventParameter(const TypedReferenceCount *ptr) : _ptr(new EventStoreTypedRefCount((TypedReferenceCount *)ptr)) { }
+
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: EventParameter::Integer constructor
 //     Function: EventParameter::Integer constructor
@@ -236,6 +254,36 @@ get_wstring_value() const {
   return ((const EventStoreWstring *)_ptr.p())->get_value();
   return ((const EventStoreWstring *)_ptr.p())->get_value();
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: EventParameter::is_typed_ref_count
+//       Access: Public
+//  Description: Returns true if the EventParameter stores a
+//               TypedReferenceCount pointer, false otherwise.  Note
+//               that a TypedReferenceCount is not exactly the same
+//               kind of pointer as a TypedWritableReferenceCount,
+//               hence the need for this separate call.
+////////////////////////////////////////////////////////////////////
+INLINE bool EventParameter::
+is_typed_ref_count() const {
+  if (is_empty()) {
+    return false;
+  }
+  return _ptr->is_of_type(EventStoreTypedRefCount::get_class_type());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EventParameter::get_typed_ref_count_value
+//       Access: Public
+//  Description: Retrieves the value stored in the EventParameter.  It
+//               is only valid to call this if is_typed_ref_count()
+//               has already returned true.
+////////////////////////////////////////////////////////////////////
+INLINE TypedReferenceCount *EventParameter::
+get_typed_ref_count_value() const {
+  nassertr(is_typed_ref_count(), NULL);
+  return ((const EventStoreTypedRefCount *)_ptr.p())->get_value();
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: EventParameter::get_ptr
 //     Function: EventParameter::get_ptr
 //       Access: Public
 //       Access: Public
@@ -275,6 +323,40 @@ INLINE EventStoreValueBase::
 ~EventStoreValueBase() {
 ~EventStoreValueBase() {
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: EventStoreTypedRefCount::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE EventStoreTypedRefCount::
+EventStoreTypedRefCount(const TypedReferenceCount *value) : 
+  _value((TypedReferenceCount *)value) 
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EventStoreTypedRefCount::set_value
+//       Access: Public
+//  Description: Changes the value stored in the parameter.  It is
+//               dangerous to do this for a parameter already added to
+//               an event, since the parameters may be shared.
+////////////////////////////////////////////////////////////////////
+INLINE void EventStoreTypedRefCount::
+set_value(const TypedReferenceCount *value) {
+  _value = (TypedReferenceCount *)value;
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: EventStoreTypedRefCount::get_value
+//       Access: Public
+//  Description: Retrieves the value stored in the parameter.
+////////////////////////////////////////////////////////////////////
+INLINE TypedReferenceCount *EventStoreTypedRefCount::
+get_value() const {
+  return _value;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: EventStoreValue::Default Constructor
 //     Function: EventStoreValue::Default Constructor
 //       Access: Private
 //       Access: Private

+ 16 - 53
panda/src/event/eventParameter.cxx

@@ -25,59 +25,7 @@
 #endif
 #endif
 
 
 TypeHandle EventStoreValueBase::_type_handle;
 TypeHandle EventStoreValueBase::_type_handle;
-
-////////////////////////////////////////////////////////////////////
-//     Function: EventParameter::Pointer constructor
-//       Access: Public
-//  Description: Defines an EventParameter that stores a pointer to
-//               a TypedReferenceCount object.  Note that a
-//               TypedReferenceCount is not the same kind of pointer
-//               as a TypedWritableReferenceCount, hence we require
-//               both constructors.
-//
-//               This accepts a const pointer, even though it stores
-//               (and eventually returns) a non-const pointer.  This
-//               is just the simplest way to allow both const and
-//               non-const pointers to be stored, but it does lose the
-//               constness.  Be careful.
-//
-//               This constructor, and the accessors for this type of
-//               event parameter, are declared non-inline so we don't
-//               have to worry about exporting this template class
-//               from this DLL.
-////////////////////////////////////////////////////////////////////
-EventParameter::
-EventParameter(const TypedReferenceCount *ptr) : _ptr(new EventStoreTypedRefCount((TypedReferenceCount *)ptr)) { }
-
-////////////////////////////////////////////////////////////////////
-//     Function: EventParameter::is_typed_ref_count
-//       Access: Public
-//  Description: Returns true if the EventParameter stores a
-//               TypedReferenceCount pointer, false otherwise.  Note
-//               that a TypedReferenceCount is not exactly the same
-//               kind of pointer as a TypedWritableReferenceCount,
-//               hence the need for this separate call.
-////////////////////////////////////////////////////////////////////
-bool EventParameter::
-is_typed_ref_count() const {
-  if (is_empty()) {
-    return false;
-  }
-  return _ptr->is_of_type(EventStoreTypedRefCount::get_class_type());
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: EventParameter::get_typed_ref_count_value
-//       Access: Public
-//  Description: Retrieves the value stored in the EventParameter.  It
-//               is only valid to call this if is_typed_ref_count()
-//               has already returned true.
-////////////////////////////////////////////////////////////////////
-TypedReferenceCount *EventParameter::
-get_typed_ref_count_value() const {
-  nassertr(is_typed_ref_count(), NULL);
-  return ((const EventStoreTypedRefCount *)_ptr.p())->get_value();
-}
+TypeHandle EventStoreTypedRefCount::_type_handle;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: EventParameter::output
 //     Function: EventParameter::output
@@ -98,3 +46,18 @@ output(ostream &out) const {
     out << _ptr->get_type();
     out << _ptr->get_type();
   }
   }
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: EventStoreTypedRefCount::output
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void EventStoreTypedRefCount::
+output(ostream &out) const {
+  if (_value == (TypedReferenceCount *)NULL) {
+    out << "(empty)";
+
+  } else {
+    out << _value->get_type();
+  }
+}

+ 38 - 4
panda/src/event/eventParameter.h

@@ -43,7 +43,7 @@ class EXPCL_PANDA EventParameter {
 PUBLISHED:
 PUBLISHED:
   INLINE EventParameter();
   INLINE EventParameter();
   INLINE EventParameter(const TypedWritableReferenceCount *ptr);
   INLINE EventParameter(const TypedWritableReferenceCount *ptr);
-  EventParameter(const TypedReferenceCount *ptr);
+  INLINE EventParameter(const TypedReferenceCount *ptr);
   INLINE EventParameter(int value);
   INLINE EventParameter(int value);
   INLINE EventParameter(double value);
   INLINE EventParameter(double value);
   INLINE EventParameter(const string &value);
   INLINE EventParameter(const string &value);
@@ -68,8 +68,8 @@ PUBLISHED:
   INLINE bool is_wstring() const;
   INLINE bool is_wstring() const;
   INLINE wstring get_wstring_value() const;
   INLINE wstring get_wstring_value() const;
 
 
-  bool is_typed_ref_count() const;
-  TypedReferenceCount *get_typed_ref_count_value() const;
+  INLINE bool is_typed_ref_count() const;
+  INLINE TypedReferenceCount *get_typed_ref_count_value() const;
 
 
   INLINE TypedWritableReferenceCount *get_ptr() const;
   INLINE TypedWritableReferenceCount *get_ptr() const;
 
 
@@ -111,6 +111,41 @@ private:
   static TypeHandle _type_handle;
   static TypeHandle _type_handle;
 };
 };
 
 
+////////////////////////////////////////////////////////////////////
+//       Class : EventStoreTypedRefCount
+// Description : A class object for storing specifically objects of
+//               type TypedReferenceCount, which is different than
+//               TypedWritableReferenceCount.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA EventStoreTypedRefCount : public EventStoreValueBase {
+public:
+  INLINE EventStoreTypedRefCount(const TypedReferenceCount *value);
+
+  INLINE void set_value(const TypedReferenceCount *value);
+  INLINE TypedReferenceCount *get_value() const;
+
+  virtual void output(ostream &out) const;
+
+  PT(TypedReferenceCount) _value;
+
+public:
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    EventStoreValueBase::init_type();
+    register_type(_type_handle, "EventStoreTypedRefCount",
+                  EventStoreValueBase::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : EventStoreValue
 //       Class : EventStoreValue
 // Description : A handy class object for storing simple values (like
 // Description : A handy class object for storing simple values (like
@@ -174,7 +209,6 @@ typedef EventStoreValue<int> EventStoreInt;
 typedef EventStoreValue<double> EventStoreDouble;
 typedef EventStoreValue<double> EventStoreDouble;
 typedef EventStoreValue<string> EventStoreString;
 typedef EventStoreValue<string> EventStoreString;
 typedef EventStoreValue<wstring> EventStoreWstring;
 typedef EventStoreValue<wstring> EventStoreWstring;
-typedef EventStoreValue< PT(TypedReferenceCount) > EventStoreTypedRefCount;
 
 
 #include "eventParameter.I"
 #include "eventParameter.I"