Browse Source

minor threading fixes

David Rose 18 years ago
parent
commit
4c2659988f

+ 0 - 1
panda/src/audio/audioLoadRequest.I

@@ -26,7 +26,6 @@
 INLINE AudioLoadRequest::
 AudioLoadRequest(AudioManager *audio_manager, const string &filename, 
                  bool positional) :
-  AsyncTask(filename),
   _audio_manager(audio_manager),
   _filename(filename),
   _positional(positional),

+ 3 - 0
panda/src/audio/audioLoadRequest.h

@@ -36,6 +36,9 @@
 //               an asynchronous load.
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_AUDIO AudioLoadRequest : public AsyncTask {
+public:
+  ALLOC_DELETED_CHAIN(AudioLoadRequest);
+
 PUBLISHED:
   INLINE AudioLoadRequest(AudioManager *audio_manager, const string &filename, 
                           bool positional);

+ 1 - 2
panda/src/event/asyncTask.I

@@ -23,8 +23,7 @@
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 INLINE AsyncTask::
-AsyncTask(const string &name) : 
-  Namable(name),
+AsyncTask() : 
   _state(S_inactive),
   _manager(NULL)
 {

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

@@ -37,5 +37,5 @@ AsyncTask::
 ////////////////////////////////////////////////////////////////////
 void AsyncTask::
 output(ostream &out) const {
-  out << get_type() << " " << get_name();
+  out << get_type();
 }

+ 3 - 2
panda/src/event/asyncTask.h

@@ -43,10 +43,11 @@ class AsyncTaskManager;
 //               class, and override do_task(), to define the
 //               functionality you wish to have the task perform.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA_EVENT AsyncTask : public TypedReferenceCount, public Namable {
+class EXPCL_PANDA_EVENT AsyncTask : public TypedReferenceCount {
 public:
-  INLINE AsyncTask(const string &name);
+  INLINE AsyncTask();
   virtual ~AsyncTask();
+  ALLOC_DELETED_CHAIN(AsyncTask);
 
 PUBLISHED:
   enum State {

+ 74 - 29
panda/src/event/asyncTaskManager.cxx

@@ -194,6 +194,7 @@ remove(AsyncTask *task) {
   // serviced.  Wait for it to finish.
   while (task->_manager == this && 
          task->_state == AsyncTask::S_servicing) {
+    PStatTimer timer(_wait_pcollector);
     _cvar.wait();
   }
 
@@ -235,6 +236,37 @@ has_task(AsyncTask *task) const {
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: AsyncTaskManager::wait_for_tasks
+//       Access: Published
+//  Description: Blocks until the task list is empty.
+////////////////////////////////////////////////////////////////////
+void AsyncTaskManager::
+wait_for_tasks() {
+  MutexHolder holder(_lock);
+
+  if (_threads.empty()) {
+    // Non-threaded case.
+    while (!_active.empty()) {
+      if (_state == AsyncTaskManager::S_shutdown) {
+        return;
+      }
+      do_poll();
+    }
+
+  } else {
+    // Threaded case.
+    while (_num_tasks > 0) {
+      if (_state == AsyncTaskManager::S_shutdown) {
+        return;
+      }
+      
+      PStatTimer timer(_wait_pcollector);
+      _cvar.wait();
+    }
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: AsyncTaskManager::poll
 //       Access: Published
@@ -250,32 +282,8 @@ poll() {
   if (!_threads.empty()) {
     return;
   }
-
-  Tasks new_active;
-  int new_num_tasks = 0;
-  Tasks::iterator ti;
-  for (ti = _active.begin(); ti != _active.end(); ++ti) {
-    AsyncTask *task = (*ti);
-    nassertv(task->_state == AsyncTask::S_active);
-    task->_state = AsyncTask::S_servicing;
-
-    // Here we keep the manager lock held while we are servicing each
-    // task.  This is the single-threaded implementation, after all,
-    // so what difference should it make?
-    if (task->do_task()) {
-      new_active.push_back(task);
-      ++new_num_tasks;
-      task->_state = AsyncTask::S_active;
-
-    } else {
-      // The task has finished.
-      task_done(task);
-    }
-  }
-
-  _active.swap(new_active);
-  _num_tasks = new_num_tasks;
-  _cvar.signal_all();
+  
+  do_poll();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -417,7 +425,9 @@ do_start_threads() {
     if (Thread::is_threading_supported()) {
       _threads.reserve(_num_threads);
       for (int i = 0; i < _num_threads; ++i) {
-        PT(AsyncTaskManagerThread) thread = new AsyncTaskManagerThread(this);
+        ostringstream strm;
+        strm << get_name() << "_" << i;
+        PT(AsyncTaskManagerThread) thread = new AsyncTaskManagerThread(strm.str(), this);
         if (thread->start(TP_low, true)) {
           _threads.push_back(thread);
         }
@@ -426,14 +436,49 @@ do_start_threads() {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: AsyncTaskManager::do_poll
+//       Access: Protected
+//  Description: The private implementation of poll(), this assumes
+//               the lock is already held.
+////////////////////////////////////////////////////////////////////
+void AsyncTaskManager::
+do_poll() {
+  Tasks new_active;
+  int new_num_tasks = 0;
+  Tasks::iterator ti;
+  for (ti = _active.begin(); ti != _active.end(); ++ti) {
+    AsyncTask *task = (*ti);
+    nassertv(task->_state == AsyncTask::S_active);
+    task->_state = AsyncTask::S_servicing;
+
+    // Here we keep the manager lock held while we are servicing each
+    // task.  This is the single-threaded implementation, after all,
+    // so what difference should it make?
+    if (task->do_task()) {
+      new_active.push_back(task);
+      ++new_num_tasks;
+      task->_state = AsyncTask::S_active;
+
+    } else {
+      // The task has finished.
+      task_done(task);
+    }
+  }
+
+  _active.swap(new_active);
+  _num_tasks = new_num_tasks;
+  _cvar.signal_all();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: AsyncTaskManager::AsyncTaskManagerThread::Constructor
 //       Access: Public
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 AsyncTaskManager::AsyncTaskManagerThread::
-AsyncTaskManagerThread(AsyncTaskManager *manager) :
-  Thread(manager->get_name(), manager->get_name()),
+AsyncTaskManagerThread(const string &name, AsyncTaskManager *manager) :
+  Thread(name, manager->get_name()),
   _manager(manager),
   _servicing(NULL)
 {

+ 5 - 2
panda/src/event/asyncTaskManager.h

@@ -50,7 +50,7 @@
 class EXPCL_PANDA_EVENT AsyncTaskManager : public TypedReferenceCount, public Namable {
 PUBLISHED:
   AsyncTaskManager(const string &name, int num_threads);
-  virtual ~AsyncTaskManager();
+  BLOCKING virtual ~AsyncTaskManager();
 
   INLINE int get_num_threads() const;
   BLOCKING void stop_threads();
@@ -62,6 +62,8 @@ PUBLISHED:
   bool remove(AsyncTask *task);
   bool has_task(AsyncTask *task) const;
 
+  BLOCKING void wait_for_tasks();
+
   INLINE int get_num_tasks() const;
 
   void poll();
@@ -76,11 +78,12 @@ protected:
   void service_one_task(AsyncTaskManagerThread *thread);
   void task_done(AsyncTask *task);
   void do_start_threads();
+  void do_poll();
 
 protected:
   class AsyncTaskManagerThread : public Thread {
   public:
-    AsyncTaskManagerThread(AsyncTaskManager *manager);
+    AsyncTaskManagerThread(const string &name, AsyncTaskManager *manager);
     virtual void thread_main();
 
     AsyncTaskManager *_manager;

+ 1 - 0
panda/src/grutil/pipeOcclusionCullTraverser.cxx

@@ -251,6 +251,7 @@ end_traverse() {
 #endif  // NDEBUG
   }
   _pending_objects.clear();
+  CullTraverser::end_traverse();
 
   gsg->end_scene();
   _buffer->end_frame(GraphicsOutput::FM_render, current_thread);

+ 20 - 0
panda/src/pgraph/cullHandler.cxx

@@ -23,6 +23,15 @@
 #include "renderState.h"
 #include "pnotify.h"
 
+////////////////////////////////////////////////////////////////////
+//     Function: CullHandler::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+CullHandler::
+CullHandler() {
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CullHandler::Destructor
 //       Access: Public, Virtual
@@ -50,6 +59,17 @@ record_object(CullableObject *object, const CullTraverser *traverser) {
   delete object;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CullHandler::end_traverse
+//       Access: Public, Virtual
+//  Description: This callback function is intended to be overridden
+//               by a derived class.  This is called at the end of the
+//               traversal.
+////////////////////////////////////////////////////////////////////
+void CullHandler::
+end_traverse() {
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CullHandler::draw_with_decals
 //       Access: Public, Static

+ 2 - 0
panda/src/pgraph/cullHandler.h

@@ -34,10 +34,12 @@ class CullTraverser;
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_PGRAPH CullHandler {
 public:
+  CullHandler();
   virtual ~CullHandler();
 
   virtual void record_object(CullableObject *object, 
                              const CullTraverser *traverser);
+  virtual void end_traverse();
 
   INLINE static void draw(CullableObject *object,
                           GraphicsStateGuardianBase *gsg,

+ 0 - 13
panda/src/pgraph/cullResult.I

@@ -17,19 +17,6 @@
 ////////////////////////////////////////////////////////////////////
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: CullResult::Constructor
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE CullResult::
-CullResult(GraphicsStateGuardianBase *gsg,
-           const PStatCollector &draw_region_pcollector) :
-  _gsg(gsg),
-  _draw_region_pcollector(draw_region_pcollector)
-{
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: CullResult::Destructor
 //       Access: Public

+ 13 - 0
panda/src/pgraph/cullResult.cxx

@@ -56,6 +56,19 @@
 static const float dual_opaque_level = 252.0f / 256.0f;
 static const double bin_color_flash_rate = 1.0;  // 1 state change per second
 
+////////////////////////////////////////////////////////////////////
+//     Function: CullResult::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+CullResult::
+CullResult(GraphicsStateGuardianBase *gsg,
+           const PStatCollector &draw_region_pcollector) :
+  _gsg(gsg),
+  _draw_region_pcollector(draw_region_pcollector)
+{
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CullResult::make_next
 //       Access: Public

+ 3 - 4
panda/src/pgraph/cullResult.h

@@ -24,7 +24,6 @@
 #include "renderState.h"
 #include "cullableObject.h"
 #include "geomMunger.h"
-
 #include "referenceCount.h"
 #include "pointerTo.h"
 #include "pvector.h"
@@ -51,8 +50,8 @@ class SceneSetup;
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_PGRAPH CullResult : public ReferenceCount {
 public:
-  INLINE CullResult(GraphicsStateGuardianBase *gsg,
-                    const PStatCollector &draw_region_pcollector);
+  CullResult(GraphicsStateGuardianBase *gsg,
+             const PStatCollector &draw_region_pcollector);
   INLINE ~CullResult();
 
   PT(CullResult) make_next() const;
@@ -81,7 +80,7 @@ private:
 
   GraphicsStateGuardianBase *_gsg;
   PStatCollector _draw_region_pcollector;
-
+  
   typedef pvector< PT(CullBin) > Bins;
   Bins _bins;
 };

+ 1 - 0
panda/src/pgraph/cullTraverser.cxx

@@ -359,6 +359,7 @@ traverse_below(CullTraverserData &data) {
 ////////////////////////////////////////////////////////////////////
 void CullTraverser::
 end_traverse() {
+  _cull_handler->end_traverse();
 }
 
 ////////////////////////////////////////////////////////////////////

+ 0 - 1
panda/src/pgraph/modelFlattenRequest.I

@@ -25,7 +25,6 @@
 ////////////////////////////////////////////////////////////////////
 INLINE ModelFlattenRequest::
 ModelFlattenRequest(PandaNode *orig) :
-  AsyncTask(orig->get_name()),
   _orig(orig),
   _is_ready(false)
 {

+ 3 - 0
panda/src/pgraph/modelFlattenRequest.h

@@ -35,6 +35,9 @@
 //               retrieved from this object.
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_PGRAPH ModelFlattenRequest : public AsyncTask {
+public:
+  ALLOC_DELETED_CHAIN(ModelFlattenRequest);
+
 PUBLISHED:
   INLINE ModelFlattenRequest(PandaNode *orig);
   

+ 0 - 1
panda/src/pgraph/modelLoadRequest.I

@@ -25,7 +25,6 @@
 ////////////////////////////////////////////////////////////////////
 INLINE ModelLoadRequest::
 ModelLoadRequest(const Filename &filename, const LoaderOptions &options) :
-  AsyncTask(filename),
   _filename(filename),
   _options(options),
   _is_ready(false)

+ 3 - 0
panda/src/pgraph/modelLoadRequest.h

@@ -35,6 +35,9 @@
 //               an asynchronous load.
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_PGRAPH ModelLoadRequest : public AsyncTask {
+public:
+  ALLOC_DELETED_CHAIN(ModelLoadRequest);
+
 PUBLISHED:
   INLINE ModelLoadRequest(const Filename &filename, 
                           const LoaderOptions &options);