15 #include "asyncTaskManager.h"
18 #include "mutexHolder.h"
20 #include "pStatClient.h"
21 #include "pStatTimer.h"
22 #include "clockObject.h"
23 #include "config_event.h"
36 AsyncTaskManager(
const string &name) :
38 _lock(
"AsyncTaskManager::_lock"),
44 do_make_task_chain(
"default");
67 if (task_cat.is_debug()) {
68 do_output(task_cat.debug());
75 while (!_task_chains.
empty()) {
83 if (_num_tasks == 1) {
84 nassertv(_tasks_by_name.size() == 1);
85 TasksByName::const_iterator tbni = _tasks_by_name.begin();
87 nassertv(task->_state == AsyncTask::S_servicing ||
88 task->_state == AsyncTask::S_servicing_removed);
89 task->_state = AsyncTask::S_servicing_removed;
95 nassertd(_num_tasks == 0 && _tasks_by_name.empty()) {
97 <<
"_num_tasks = " << _num_tasks <<
" _tasks_by_name = " << _tasks_by_name.size() <<
"\n";
98 TasksByName::const_iterator tbni;
99 for (tbni = _tasks_by_name.begin();
100 tbni != _tasks_by_name.end();
103 <<
" " << *(*tbni) <<
"\n";
118 return _task_chains.
size();
129 nassertr(n >= 0 && n < (
int)_task_chains.
size(), NULL);
130 return _task_chains[n];
144 return do_make_task_chain(name);
156 return do_find_task_chain(name);
174 TaskChains::iterator tci = _task_chains.find(chain);
175 if (tci == _task_chains.
end()) {
182 while (chain->_num_tasks != 0) {
185 <<
"Waiting for tasks on chain " << name <<
" to finish.\n";
186 chain->do_wait_for_tasks();
191 _task_chains.erase(tci);
204 nassertv(task->is_runnable());
209 if (task_cat.is_debug()) {
211 <<
"Adding " << *task <<
"\n";
214 if (task->_state == AsyncTask::S_servicing_removed) {
215 if (task->_manager ==
this) {
218 task->_state = AsyncTask::S_servicing;
223 nassertv(task->_manager == NULL &&
224 task->_state == AsyncTask::S_inactive);
225 nassertv(!do_has_task(task));
228 task->upon_birth(
this);
230 nassertv(task->_manager == NULL &&
231 task->_state == AsyncTask::S_inactive);
232 nassertv(!do_has_task(task));
237 <<
"Creating implicit AsyncTaskChain " << task->_chain_name
238 <<
" for " << get_type() <<
" " << get_name() <<
"\n";
239 chain = do_make_task_chain(task->_chain_name);
255 if (task->_manager !=
this) {
256 nassertr(!do_has_task(task),
false);
260 if (task->_state == AsyncTask::S_servicing_removed) {
283 TasksByName::const_iterator tbni = _tasks_by_name.lower_bound(&sample_task);
284 if (tbni != _tasks_by_name.end() && (*tbni)->get_name() == name) {
302 TasksByName::const_iterator tbni = _tasks_by_name.lower_bound(&sample_task);
304 while (tbni != _tasks_by_name.end() && (*tbni)->get_name() == name) {
324 TasksByName::const_iterator tbni = _tasks_by_name.lower_bound(&sample_task);
326 while (tbni != _tasks_by_name.end() && (*tbni)->get_name().substr(0, prefix.size()) == prefix) {
328 if (pattern.
matches(task->get_name())) {
351 return remove(tasks) != 0;
367 for (i = 0; i < num_tasks; ++i) {
370 if (task->_manager !=
this) {
372 nassertr(!do_has_task(task), num_removed);
374 nassertr(task->_chain->_manager ==
this, num_removed);
375 if (task_cat.is_debug()) {
377 <<
"Removing " << *task <<
"\n";
379 if (task->_chain->do_remove(task)) {
381 task->upon_death(
this,
false);
385 if (task_cat.is_debug()) {
387 <<
" (unable to remove " << *task <<
")\n";
406 while (_num_tasks > 0) {
410 for (
unsigned int i = 0; i < _task_chains.
size(); ++i) {
412 chain->do_wait_for_tasks();
432 for (
unsigned int i = 0; i < _task_chains.
size(); ++i) {
434 chain->do_stop_threads();
452 for (
unsigned int i = 0; i < _task_chains.
size(); ++i) {
455 chain->do_start_threads();
470 TaskChains::const_iterator tci;
471 for (tci = _task_chains.
begin();
472 tci != _task_chains.
end();
494 TaskChains::const_iterator tci;
495 for (tci = _task_chains.
begin();
496 tci != _task_chains.
end();
517 TaskChains::const_iterator tci;
518 for (tci = _task_chains.
begin();
519 tci != _task_chains.
end();
544 for (
unsigned int i = 0; i < _task_chains.
size(); ++i) {
565 bool got_any =
false;
566 double next_wake_time = -1.0;
568 TaskChains::const_iterator tci;
569 for (tci = _task_chains.
begin();
570 tci != _task_chains.
end();
573 double time = chain->do_get_next_wake_time();
577 next_wake_time = time;
579 next_wake_time = min(time, next_wake_time);
584 return next_wake_time;
592 void AsyncTaskManager::
593 output(ostream &out)
const {
603 void AsyncTaskManager::
604 write(ostream &out,
int indent_level)
const {
606 indent(out, indent_level)
607 << get_type() <<
" " << get_name() <<
"\n";
609 TaskChains::const_iterator tci;
610 for (tci = _task_chains.
begin();
611 tci != _task_chains.
end();
614 if (chain->_num_tasks != 0) {
616 chain->do_write(out, indent_level + 2);
632 do_make_task_chain(
const string &name) {
635 TaskChains::const_iterator tci = _task_chains.insert(chain).first;
648 do_find_task_chain(const
string &name) {
651 TaskChains::const_iterator tci = _task_chains.find(chain);
652 if (tci != _task_chains.end()) {
665 void AsyncTaskManager::
667 if (!task->get_name().empty()) {
670 TasksByName::iterator tbni = _tasks_by_name.lower_bound(task);
671 while (tbni != _tasks_by_name.end()) {
672 if ((*tbni) == task) {
673 _tasks_by_name.erase(tbni);
676 if ((*tbni)->get_name() != task->get_name()) {
697 bool AsyncTaskManager::
699 TaskChains::const_iterator tci;
700 for (tci = _task_chains.
begin();
701 tci != _task_chains.
end();
704 if (chain->do_has_task(task)) {
717 void AsyncTaskManager::
718 do_output(ostream &out)
const {
719 out << get_type() <<
" " << get_name()
720 <<
"; " << _num_tasks <<
" tasks";
729 void AsyncTaskManager::
AsyncTaskCollection get_tasks() const
Returns the set of tasks that are active or sleeping on the task manager, at the time of the call...
AsyncTaskChain * make_task_chain(const string &name)
Creates a new AsyncTaskChain of the indicated name and stores it within the AsyncTaskManager.
void pop_back()
Removes the last element at the end of the vector.
bool remove(AsyncTask *task)
Removes the indicated task from the active queue.
bool empty() const
Returns true if the ordered vector is empty, false otherwise.
A class to manage a loose queue of isolated tasks, which can be performed either synchronously (in th...
AsyncTask * find_task(const string &name) const
Returns the first task found with the indicated name, or NULL if there is no task with the indicated ...
int get_num_tasks() const
Returns the number of AsyncTasks in the collection.
void start_threads()
Starts any requested threads to service the tasks on the queue.
void cleanup()
Stops all threads and messily empties the task list.
iterator_0 begin()
Returns the iterator that marks the first element in the ordered vector.
bool remove_task_chain(const string &name)
Removes the AsyncTaskChain of the indicated name.
void add_task(AsyncTask *task)
Adds a new AsyncTask to the collection.
A list of tasks, for instance as returned by some of the AsyncTaskManager query functions.
bool has_task(AsyncTask *task) const
Returns true if the indicated task has been added to this AsyncTaskManager, false otherwise...
bool matches(const string &candidate) const
Returns true if the candidate string matches the pattern, false otherwise.
A lightweight C++ object whose constructor calls acquire() and whose destructor calls release() on a ...
iterator_0 end()
Returns the iterator that marks the end of the ordered vector.
void notify_all()
Informs all of the other threads who are currently blocked on wait() that the relevant condition has ...
string get_const_prefix() const
Returns the initial part of the pattern before the first glob character.
void acquire() const
Grabs the mutex if it is available.
int get_num_task_chains() const
Returns the number of different task chains.
A base class for all things which can have a name.
void wait_for_tasks()
Blocks until the task list is empty.
void stop_threads()
Stops any threads that are currently running.
void add(AsyncTask *task)
Adds the indicated task to the active queue.
A ClockObject keeps track of elapsed real time and discrete time.
AsyncTaskCollection get_sleeping_tasks() const
Returns the set of tasks that are sleeping (and not active) on the task manager, at the time of the c...
void add_tasks_from(const AsyncTaskCollection &other)
Adds all the AsyncTasks indicated in the other collection to this task.
The AsyncTaskChain is a subset of the AsyncTaskManager.
AsyncTaskCollection get_active_tasks() const
Returns the set of tasks that are active (and not sleeping) on the task manager, at the time of the c...
AsyncTaskCollection find_tasks_matching(const GlobPattern &pattern) const
Returns the list of tasks found whose name matches the indicated glob pattern, e.g.
void release() const
Releases the mutex.
void local_object()
This function should be called, once, immediately after creating a new instance of some ReferenceCoun...
AsyncTaskCollection find_tasks(const string &name) const
Returns the list of tasks found with the indicated name.
AsyncTask * get_task(int index) const
Returns the nth AsyncTask in the collection.
This class represents a concrete task performed by an AsyncManager.
double get_next_wake_time() const
Returns the scheduled time (on the manager's clock) of the next sleeping task, on any task chain...
size_type_0 size() const
Returns the number of elements in the ordered vector.
void ref() const
Explicitly increments the reference count.
AsyncTaskChain * find_task_chain(const string &name)
Searches a new AsyncTaskChain of the indicated name and returns it if it exists, or NULL otherwise...
TypeHandle is the identifier used to differentiate C++ class types.
AsyncTaskChain * get_task_chain(int n) const
Returns the nth task chain.
This class can be used to test for string matches against standard Unix-shell filename globbing conve...
void poll()
Runs through all the tasks in the task list, once, if the task manager is running in single-threaded ...