Panda3D
|
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 }