Panda3D

asyncTaskManager.cxx

00001 // Filename: asyncTaskManager.cxx
00002 // Created by:  drose (23Aug06)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "asyncTaskManager.h"
00016 #include "event.h"
00017 #include "pt_Event.h"
00018 #include "mutexHolder.h"
00019 #include "indent.h"
00020 #include "pStatClient.h"
00021 #include "pStatTimer.h"
00022 #include "clockObject.h"
00023 #include "config_event.h"
00024 #include <algorithm>
00025 
00026 PT(AsyncTaskManager) AsyncTaskManager::_global_ptr;
00027 
00028 TypeHandle AsyncTaskManager::_type_handle;
00029 
00030 ////////////////////////////////////////////////////////////////////
00031 //     Function: AsyncTaskManager::Constructor
00032 //       Access: Published
00033 //  Description:
00034 ////////////////////////////////////////////////////////////////////
00035 AsyncTaskManager::
00036 AsyncTaskManager(const string &name) :
00037   Namable(name),
00038   _lock("AsyncTaskManager::_lock"),
00039   _num_tasks(0),
00040   _clock(ClockObject::get_global_clock()),
00041   _frame_cvar(_lock)
00042 {
00043   // Make a default task chain.
00044   do_make_task_chain("default");
00045 }
00046 
00047 ////////////////////////////////////////////////////////////////////
00048 //     Function: AsyncTaskManager::Destructor
00049 //       Access: Published, Virtual
00050 //  Description:
00051 ////////////////////////////////////////////////////////////////////
00052 AsyncTaskManager::
00053 ~AsyncTaskManager() {
00054   cleanup();
00055 }
00056 
00057 ////////////////////////////////////////////////////////////////////
00058 //     Function: AsyncTaskManager::cleanup
00059 //       Access: Published
00060 //  Description: Stops all threads and messily empties the task list.
00061 //               This is intended to be called on destruction only.
00062 ////////////////////////////////////////////////////////////////////
00063 void AsyncTaskManager::
00064 cleanup() {
00065   MutexHolder holder(_lock);
00066 
00067   if (task_cat.is_debug()) {
00068     do_output(task_cat.debug());
00069     task_cat.debug(false)
00070       << ": cleanup()\n";
00071   }
00072 
00073   // Iterate carefully in case the tasks adjust the chain list within
00074   // cleanup().
00075   while (!_task_chains.empty()) {
00076     PT(AsyncTaskChain) chain = _task_chains[_task_chains.size() - 1];
00077     _task_chains.pop_back();
00078     chain->do_cleanup();
00079   }
00080 
00081   // There might be one remaining task, the current task.  Especially
00082   // if it wasn't running on a thread.
00083   if (_num_tasks == 1) {
00084     nassertv(_tasks_by_name.size() == 1);
00085     TasksByName::const_iterator tbni = _tasks_by_name.begin();
00086     AsyncTask *task = (*tbni);
00087     nassertv(task->_state == AsyncTask::S_servicing || 
00088              task->_state == AsyncTask::S_servicing_removed);
00089     task->_state = AsyncTask::S_servicing_removed;
00090 
00091   } else {
00092     // If there isn't exactly one remaining task, there should be
00093     // none.
00094 #ifndef NDEBUG
00095     nassertd(_num_tasks == 0 && _tasks_by_name.empty()) {
00096       task_cat.error()
00097         << "_num_tasks = " << _num_tasks << " _tasks_by_name = " << _tasks_by_name.size() << "\n";
00098       TasksByName::const_iterator tbni;
00099       for (tbni = _tasks_by_name.begin();
00100            tbni != _tasks_by_name.end();
00101            ++tbni) {
00102         task_cat.error()
00103           << "  " << *(*tbni) << "\n";
00104       }
00105     }
00106 #endif  // NDEBUG
00107   }
00108 }
00109 
00110 ////////////////////////////////////////////////////////////////////
00111 //     Function: AsyncTaskManager::get_num_task_chains
00112 //       Access: Published
00113 //  Description: Returns the number of different task chains.
00114 ////////////////////////////////////////////////////////////////////
00115 int AsyncTaskManager::
00116 get_num_task_chains() const {
00117   MutexHolder holder(_lock);
00118   return _task_chains.size();
00119 }
00120 
00121 ////////////////////////////////////////////////////////////////////
00122 //     Function: AsyncTaskManager::get_task_chain
00123 //       Access: Published
00124 //  Description: Returns the nth task chain.
00125 ////////////////////////////////////////////////////////////////////
00126 AsyncTaskChain *AsyncTaskManager::
00127 get_task_chain(int n) const {
00128   MutexHolder holder(_lock);
00129   nassertr(n >= 0 && n < (int)_task_chains.size(), NULL);
00130   return _task_chains[n];
00131 }
00132 
00133 ////////////////////////////////////////////////////////////////////
00134 //     Function: AsyncTaskManager::make_task_chain
00135 //       Access: Published
00136 //  Description: Creates a new AsyncTaskChain of the indicated name
00137 //               and stores it within the AsyncTaskManager.  If a task
00138 //               chain with this name already exists, returns it
00139 //               instead.
00140 ////////////////////////////////////////////////////////////////////
00141 AsyncTaskChain *AsyncTaskManager::
00142 make_task_chain(const string &name) {
00143   MutexHolder holder(_lock);
00144   return do_make_task_chain(name);
00145 }
00146 
00147 ////////////////////////////////////////////////////////////////////
00148 //     Function: AsyncTaskManager::find_task_chain
00149 //       Access: Protected
00150 //  Description: Searches a new AsyncTaskChain of the indicated name
00151 //               and returns it if it exists, or NULL otherwise.
00152 ////////////////////////////////////////////////////////////////////
00153 AsyncTaskChain *AsyncTaskManager::
00154 find_task_chain(const string &name) {
00155   MutexHolder holder(_lock);
00156   return do_find_task_chain(name);
00157 }
00158 
00159 ////////////////////////////////////////////////////////////////////
00160 //     Function: AsyncTaskManager::remove_task_chain
00161 //       Access: Protected
00162 //  Description: Removes the AsyncTaskChain of the indicated name.
00163 //               If the chain still has tasks, this will block until
00164 //               all tasks are finished.
00165 //
00166 //               Returns true if successful, or false if the chain did
00167 //               not exist.
00168 ////////////////////////////////////////////////////////////////////
00169 bool AsyncTaskManager::
00170 remove_task_chain(const string &name) {
00171   MutexHolder holder(_lock);
00172 
00173   PT(AsyncTaskChain) chain = new AsyncTaskChain(this, name);
00174   TaskChains::iterator tci = _task_chains.find(chain);
00175   if (tci == _task_chains.end()) {
00176     // No chain.
00177     return false;
00178   }
00179 
00180   chain = (*tci);
00181 
00182   while (chain->_num_tasks != 0) {
00183     // Still has tasks.
00184     task_cat.info()
00185       << "Waiting for tasks on chain " << name << " to finish.\n";
00186     chain->do_wait_for_tasks();
00187   }
00188 
00189   // Safe to remove.
00190   chain->do_cleanup();
00191   _task_chains.erase(tci);
00192   return true;
00193 }
00194 
00195 ////////////////////////////////////////////////////////////////////
00196 //     Function: AsyncTaskManager::add
00197 //       Access: Published
00198 //  Description: Adds the indicated task to the active queue.  It is
00199 //               an error if the task is already added to this or any
00200 //               other active queue.
00201 ////////////////////////////////////////////////////////////////////
00202 void AsyncTaskManager::
00203 add(AsyncTask *task) {
00204   nassertv(task->is_runnable());
00205 
00206   {
00207     MutexHolder holder(_lock);
00208     
00209     if (task_cat.is_debug()) {
00210       task_cat.debug()
00211         << "Adding " << *task << "\n";
00212     }
00213     
00214     if (task->_state == AsyncTask::S_servicing_removed) {
00215       if (task->_manager == this) {
00216         // Re-adding a self-removed task; this just means clearing the
00217         // removed flag.
00218         task->_state = AsyncTask::S_servicing;
00219         return;
00220       }
00221     }
00222     
00223     nassertv(task->_manager == NULL &&
00224              task->_state == AsyncTask::S_inactive);
00225     nassertv(!do_has_task(task));
00226 
00227     _lock.release();
00228     task->upon_birth(this);
00229     _lock.acquire();
00230     nassertv(task->_manager == NULL &&
00231              task->_state == AsyncTask::S_inactive);
00232     nassertv(!do_has_task(task));
00233     
00234     AsyncTaskChain *chain = do_find_task_chain(task->_chain_name);
00235     if (chain == (AsyncTaskChain *)NULL) {
00236       task_cat.warning()
00237         << "Creating implicit AsyncTaskChain " << task->_chain_name
00238         << " for " << get_type() << " " << get_name() << "\n";
00239       chain = do_make_task_chain(task->_chain_name);
00240     }
00241     chain->do_add(task);
00242   }
00243 }
00244 
00245 ////////////////////////////////////////////////////////////////////
00246 //     Function: AsyncTaskManager::has_task
00247 //       Access: Published
00248 //  Description: Returns true if the indicated task has been added to
00249 //               this AsyncTaskManager, false otherwise.
00250 ////////////////////////////////////////////////////////////////////
00251 bool AsyncTaskManager::
00252 has_task(AsyncTask *task) const {
00253   MutexHolder holder(_lock);
00254 
00255   if (task->_manager != this) {
00256     nassertr(!do_has_task(task), false);
00257     return false;
00258   }
00259 
00260   if (task->_state == AsyncTask::S_servicing_removed) {
00261     return false;
00262   }
00263 
00264   // The task might not actually be in the active queue, since it
00265   // might be being serviced right now.  That's OK.
00266   return true;
00267 }
00268 
00269 ////////////////////////////////////////////////////////////////////
00270 //     Function: AsyncTaskManager::find_task
00271 //       Access: Published
00272 //  Description: Returns the first task found with the indicated name,
00273 //               or NULL if there is no task with the indicated name.
00274 //
00275 //               If there are multiple tasks with the same name,
00276 //               returns one of them arbitrarily.
00277 ////////////////////////////////////////////////////////////////////
00278 AsyncTask *AsyncTaskManager::
00279 find_task(const string &name) const {
00280   AsyncTask sample_task(name);
00281   sample_task.local_object();
00282 
00283   TasksByName::const_iterator tbni = _tasks_by_name.lower_bound(&sample_task);
00284   if (tbni != _tasks_by_name.end() && (*tbni)->get_name() == name) {
00285     return (*tbni);
00286   }
00287 
00288   return NULL;
00289 }
00290 
00291 ////////////////////////////////////////////////////////////////////
00292 //     Function: AsyncTaskManager::find_tasks
00293 //       Access: Published
00294 //  Description: Returns the list of tasks found with the indicated
00295 //               name.
00296 ////////////////////////////////////////////////////////////////////
00297 AsyncTaskCollection AsyncTaskManager::
00298 find_tasks(const string &name) const {
00299   AsyncTask sample_task(name);
00300   sample_task.local_object();
00301 
00302   TasksByName::const_iterator tbni = _tasks_by_name.lower_bound(&sample_task);
00303   AsyncTaskCollection result;
00304   while (tbni != _tasks_by_name.end() && (*tbni)->get_name() == name) {
00305     result.add_task(*tbni);
00306     ++tbni;
00307   }
00308 
00309   return result;
00310 }
00311 
00312 ////////////////////////////////////////////////////////////////////
00313 //     Function: AsyncTaskManager::find_tasks_matching
00314 //       Access: Published
00315 //  Description: Returns the list of tasks found whose name matches
00316 //               the indicated glob pattern, e.g. "my_task_*".
00317 ////////////////////////////////////////////////////////////////////
00318 AsyncTaskCollection AsyncTaskManager::
00319 find_tasks_matching(const GlobPattern &pattern) const {
00320   string prefix = pattern.get_const_prefix();
00321   AsyncTask sample_task(prefix);
00322   sample_task.local_object();
00323 
00324   TasksByName::const_iterator tbni = _tasks_by_name.lower_bound(&sample_task);
00325   AsyncTaskCollection result;
00326   while (tbni != _tasks_by_name.end() && (*tbni)->get_name().substr(0, prefix.size()) == prefix) {
00327     AsyncTask *task = (*tbni);
00328     if (pattern.matches(task->get_name())) {
00329       result.add_task(task);
00330     }
00331     ++tbni;
00332   }
00333 
00334   return result;
00335 }
00336 
00337 ////////////////////////////////////////////////////////////////////
00338 //     Function: AsyncTaskManager::remove
00339 //       Access: Published
00340 //  Description: Removes the indicated task from the active queue.
00341 //               Returns true if the task is successfully removed, or
00342 //               false if it wasn't there.
00343 ////////////////////////////////////////////////////////////////////
00344 bool AsyncTaskManager::
00345 remove(AsyncTask *task) {
00346   // We pass this up to the multi-task remove() flavor.  Do we care
00347   // about the tiny cost of creating an AsyncTaskCollection here?
00348   // Probably not.
00349   AsyncTaskCollection tasks;
00350   tasks.add_task(task);
00351   return remove(tasks) != 0;
00352 }
00353 
00354 ////////////////////////////////////////////////////////////////////
00355 //     Function: AsyncTaskManager::remove
00356 //       Access: Published
00357 //  Description: Removes all of the tasks in the AsyncTaskCollection.
00358 //               Returns the number of tasks removed.
00359 ////////////////////////////////////////////////////////////////////
00360 int AsyncTaskManager::
00361 remove(const AsyncTaskCollection &tasks) {
00362   MutexHolder holder(_lock);
00363   int num_removed = 0;
00364 
00365   int num_tasks = tasks.get_num_tasks();
00366   int i;
00367   for (i = 0; i < num_tasks; ++i) {
00368     PT(AsyncTask) task = tasks.get_task(i);
00369     
00370     if (task->_manager != this) {
00371       // Not a member of this manager, or already removed.
00372       nassertr(!do_has_task(task), num_removed);
00373     } else {
00374       nassertr(task->_chain->_manager == this, num_removed);
00375       if (task_cat.is_debug()) {
00376         task_cat.debug()
00377           << "Removing " << *task << "\n";
00378       }
00379       if (task->_chain->do_remove(task)) {
00380         _lock.release();
00381         task->upon_death(this, false);
00382         _lock.acquire();
00383         ++num_removed;
00384       } else {
00385         if (task_cat.is_debug()) {
00386           task_cat.debug()
00387             << "  (unable to remove " << *task << ")\n";
00388         }
00389       }
00390     }
00391   }
00392 
00393   return num_removed;
00394 }
00395 
00396 ////////////////////////////////////////////////////////////////////
00397 //     Function: AsyncTaskManager::wait_for_tasks
00398 //       Access: Published
00399 //  Description: Blocks until the task list is empty.
00400 ////////////////////////////////////////////////////////////////////
00401 void AsyncTaskManager::
00402 wait_for_tasks() {
00403   MutexHolder holder(_lock);
00404 
00405   // Wait for each of our task chains to finish.
00406   while (_num_tasks > 0) {
00407     // We iterate through with an index, rather than with an iterator,
00408     // because it's possible for a task to adjust the task_chain list
00409     // during its execution.
00410     for (unsigned int i = 0; i < _task_chains.size(); ++i) {
00411       AsyncTaskChain *chain = _task_chains[i];
00412       chain->do_wait_for_tasks();
00413     }
00414   }
00415 }
00416 
00417 ////////////////////////////////////////////////////////////////////
00418 //     Function: AsyncTaskManager::stop_threads
00419 //       Access: Published
00420 //  Description: Stops any threads that are currently running.  If any
00421 //               tasks are still pending and have not yet been picked
00422 //               up by a thread, they will not be serviced unless
00423 //               poll() or start_threads() is later called.
00424 ////////////////////////////////////////////////////////////////////
00425 void AsyncTaskManager::
00426 stop_threads() {
00427   MutexHolder holder(_lock);
00428 
00429   // We iterate through with an index, rather than with an iterator,
00430   // because it's possible for a task to adjust the task_chain list
00431   // during its execution.
00432   for (unsigned int i = 0; i < _task_chains.size(); ++i) {
00433     AsyncTaskChain *chain = _task_chains[i];
00434     chain->do_stop_threads();
00435   }
00436 }
00437 
00438 ////////////////////////////////////////////////////////////////////
00439 //     Function: AsyncTaskManager::start_threads
00440 //       Access: Published
00441 //  Description: Starts any requested threads to service the tasks on
00442 //               the queue.  This is normally not necessary, since
00443 //               adding a task will start the threads automatically.
00444 ////////////////////////////////////////////////////////////////////
00445 void AsyncTaskManager::
00446 start_threads() {
00447   MutexHolder holder(_lock);
00448 
00449   // We iterate through with an index, rather than with an iterator,
00450   // because it's possible for a task to adjust the task_chain list
00451   // during its execution.
00452   for (unsigned int i = 0; i < _task_chains.size(); ++i) {
00453     AsyncTaskChain *chain = _task_chains[i];
00454 
00455     chain->do_start_threads();
00456   }
00457 }
00458 
00459 ////////////////////////////////////////////////////////////////////
00460 //     Function: AsyncTaskManager::get_tasks
00461 //       Access: Published
00462 //  Description: Returns the set of tasks that are active or sleeping
00463 //               on the task manager, at the time of the call.
00464 ////////////////////////////////////////////////////////////////////
00465 AsyncTaskCollection AsyncTaskManager::
00466 get_tasks() const {
00467   MutexHolder holder(_lock);
00468 
00469   AsyncTaskCollection result;
00470   TaskChains::const_iterator tci;
00471   for (tci = _task_chains.begin();
00472        tci != _task_chains.end();
00473        ++tci) {
00474     AsyncTaskChain *chain = (*tci);
00475     result.add_tasks_from(chain->do_get_active_tasks());
00476     result.add_tasks_from(chain->do_get_sleeping_tasks());
00477   }
00478 
00479   return result;
00480 }
00481 
00482 ////////////////////////////////////////////////////////////////////
00483 //     Function: AsyncTaskManager::get_active_tasks
00484 //       Access: Published
00485 //  Description: Returns the set of tasks that are active (and not
00486 //               sleeping) on the task manager, at the time of the
00487 //               call.
00488 ////////////////////////////////////////////////////////////////////
00489 AsyncTaskCollection AsyncTaskManager::
00490 get_active_tasks() const {
00491   MutexHolder holder(_lock);
00492 
00493   AsyncTaskCollection result;
00494   TaskChains::const_iterator tci;
00495   for (tci = _task_chains.begin();
00496        tci != _task_chains.end();
00497        ++tci) {
00498     AsyncTaskChain *chain = (*tci);
00499     result.add_tasks_from(chain->do_get_active_tasks());
00500   }
00501 
00502   return result;
00503 }
00504 
00505 ////////////////////////////////////////////////////////////////////
00506 //     Function: AsyncTaskManager::get_sleeping_tasks
00507 //       Access: Published
00508 //  Description: Returns the set of tasks that are sleeping (and not
00509 //               active) on the task manager, at the time of the
00510 //               call.
00511 ////////////////////////////////////////////////////////////////////
00512 AsyncTaskCollection AsyncTaskManager::
00513 get_sleeping_tasks() const {
00514   MutexHolder holder(_lock);
00515 
00516   AsyncTaskCollection result;
00517   TaskChains::const_iterator tci;
00518   for (tci = _task_chains.begin();
00519        tci != _task_chains.end();
00520        ++tci) {
00521     AsyncTaskChain *chain = (*tci);
00522     result.add_tasks_from(chain->do_get_sleeping_tasks());
00523   }
00524 
00525   return result;
00526 }
00527 
00528 ////////////////////////////////////////////////////////////////////
00529 //     Function: AsyncTaskManager::poll
00530 //       Access: Published
00531 //  Description: Runs through all the tasks in the task list, once, if
00532 //               the task manager is running in single-threaded mode
00533 //               (no threads available).  This method does nothing in
00534 //               threaded mode, so it may safely be called in either
00535 //               case.
00536 ////////////////////////////////////////////////////////////////////
00537 void AsyncTaskManager::
00538 poll() {
00539   MutexHolder holder(_lock);
00540 
00541   // We iterate through with an index, rather than with an iterator,
00542   // because it's possible for a task to adjust the task_chain list
00543   // during its execution.
00544   for (unsigned int i = 0; i < _task_chains.size(); ++i) {
00545     AsyncTaskChain *chain = _task_chains[i];
00546     chain->do_poll();
00547   }
00548 
00549   // Just in case the clock was ticked explicitly by one of our
00550   // polling chains.
00551   _frame_cvar.notify_all();
00552 }
00553 
00554 ////////////////////////////////////////////////////////////////////
00555 //     Function: AsyncTaskManager::get_next_wake_time
00556 //       Access: Published
00557 //  Description: Returns the scheduled time (on the manager's clock)
00558 //               of the next sleeping task, on any task chain, to
00559 //               awaken.  Returns -1 if there are no sleeping tasks.
00560 ////////////////////////////////////////////////////////////////////
00561 double AsyncTaskManager::
00562 get_next_wake_time() const {
00563   MutexHolder holder(_lock);
00564 
00565   bool got_any = false;
00566   double next_wake_time = -1.0;
00567 
00568   TaskChains::const_iterator tci;
00569   for (tci = _task_chains.begin();
00570        tci != _task_chains.end();
00571        ++tci) {
00572     AsyncTaskChain *chain = (*tci);
00573     double time = chain->do_get_next_wake_time();
00574     if (time >= 0.0) {
00575       if (!got_any) {
00576         got_any = true;
00577         next_wake_time = time;
00578       } else {
00579         next_wake_time = min(time, next_wake_time);
00580       }
00581     }
00582   }
00583 
00584   return next_wake_time;
00585 }
00586 
00587 ////////////////////////////////////////////////////////////////////
00588 //     Function: AsyncTaskManager::output
00589 //       Access: Published, Virtual
00590 //  Description: 
00591 ////////////////////////////////////////////////////////////////////
00592 void AsyncTaskManager::
00593 output(ostream &out) const {
00594   MutexHolder holder(_lock);
00595   do_output(out);
00596 }
00597 
00598 ////////////////////////////////////////////////////////////////////
00599 //     Function: AsyncTaskManager::write
00600 //       Access: Published, Virtual
00601 //  Description: 
00602 ////////////////////////////////////////////////////////////////////
00603 void AsyncTaskManager::
00604 write(ostream &out, int indent_level) const {
00605   MutexHolder holder(_lock);
00606   indent(out, indent_level)
00607     << get_type() << " " << get_name() << "\n";
00608 
00609   TaskChains::const_iterator tci;
00610   for (tci = _task_chains.begin();
00611        tci != _task_chains.end();
00612        ++tci) {
00613     AsyncTaskChain *chain = (*tci);
00614     if (chain->_num_tasks != 0) {
00615       out << "\n";
00616       chain->do_write(out, indent_level + 2);
00617     }
00618   }
00619 }
00620 
00621 ////////////////////////////////////////////////////////////////////
00622 //     Function: AsyncTaskManager::do_make_task_chain
00623 //       Access: Protected
00624 //  Description: Creates a new AsyncTaskChain of the indicated name
00625 //               and stores it within the AsyncTaskManager.  If a task
00626 //               chain with this name already exists, returns it
00627 //               instead.
00628 //
00629 //               Assumes the lock is held.
00630 ////////////////////////////////////////////////////////////////////
00631 AsyncTaskChain *AsyncTaskManager::
00632 do_make_task_chain(const string &name) {
00633   PT(AsyncTaskChain) chain = new AsyncTaskChain(this, name);
00634 
00635   TaskChains::const_iterator tci = _task_chains.insert(chain).first;
00636   return (*tci);
00637 }
00638 
00639 ////////////////////////////////////////////////////////////////////
00640 //     Function: AsyncTaskManager::do_find_task_chain
00641 //       Access: Protected
00642 //  Description: Searches a new AsyncTaskChain of the indicated name
00643 //               and returns it if it exists, or NULL otherwise.
00644 //
00645 //               Assumes the lock is held.
00646 ////////////////////////////////////////////////////////////////////
00647 AsyncTaskChain *AsyncTaskManager::
00648 do_find_task_chain(const string &name) {
00649   PT(AsyncTaskChain) chain = new AsyncTaskChain(this, name);
00650 
00651   TaskChains::const_iterator tci = _task_chains.find(chain);
00652   if (tci != _task_chains.end()) {
00653     return (*tci);
00654   }
00655 
00656   return NULL;
00657 }
00658 
00659 ////////////////////////////////////////////////////////////////////
00660 //     Function: AsyncTaskManager::remove_task_by_name
00661 //       Access: Protected
00662 //  Description: Removes the task from the _tasks_by_name index, if it
00663 //               has a nonempty name.
00664 ////////////////////////////////////////////////////////////////////
00665 void AsyncTaskManager::
00666 remove_task_by_name(AsyncTask *task) {
00667   if (!task->get_name().empty()) {
00668     // We have to scan linearly through all of the tasks with the same
00669     // name.
00670     TasksByName::iterator tbni = _tasks_by_name.lower_bound(task);
00671     while (tbni != _tasks_by_name.end()) {
00672       if ((*tbni) == task) {
00673         _tasks_by_name.erase(tbni);
00674         return;
00675       }
00676       if ((*tbni)->get_name() != task->get_name()) {
00677         // Too far.
00678         break;
00679       }
00680       
00681       ++tbni;
00682     }
00683 
00684     // For some reason, the task wasn't on the index.
00685     nassertv(false);
00686   }
00687 }
00688 
00689 ////////////////////////////////////////////////////////////////////
00690 //     Function: AsyncTaskManager::do_has_task
00691 //       Access: Protected
00692 //  Description: Returns true if the task is on one of the task lists,
00693 //               false if it is not (false may mean that the task is
00694 //               currently being serviced).  Assumes the lock is
00695 //               currently held.
00696 ////////////////////////////////////////////////////////////////////
00697 bool AsyncTaskManager::
00698 do_has_task(AsyncTask *task) const {
00699   TaskChains::const_iterator tci;
00700   for (tci = _task_chains.begin();
00701        tci != _task_chains.end();
00702        ++tci) {
00703     AsyncTaskChain *chain = (*tci);
00704     if (chain->do_has_task(task)) {
00705       return true;
00706     }
00707   }
00708 
00709   return false;
00710 }
00711 
00712 ////////////////////////////////////////////////////////////////////
00713 //     Function: AsyncTaskManager::do_output
00714 //       Access: Protected, Virtual
00715 //  Description: 
00716 ////////////////////////////////////////////////////////////////////
00717 void AsyncTaskManager::
00718 do_output(ostream &out) const {
00719   out << get_type() << " " << get_name()
00720       << "; " << _num_tasks << " tasks";
00721 }
00722 
00723 ////////////////////////////////////////////////////////////////////
00724 //     Function: AsyncTaskManager::make_global_ptr
00725 //       Access: Private, Static
00726 //  Description: Called once per application to create the global
00727 //               task manager object.
00728 ////////////////////////////////////////////////////////////////////
00729 void AsyncTaskManager::
00730 make_global_ptr() {
00731   nassertv(_global_ptr == (AsyncTaskManager *)NULL);
00732 
00733   _global_ptr = new AsyncTaskManager("TaskManager");
00734 }
 All Classes Functions Variables Enumerations