Panda3D
 All Classes Functions Variables Enumerations
asyncTaskManager.cxx
1 // Filename: asyncTaskManager.cxx
2 // Created by: drose (23Aug06)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "asyncTaskManager.h"
16 #include "event.h"
17 #include "pt_Event.h"
18 #include "mutexHolder.h"
19 #include "indent.h"
20 #include "pStatClient.h"
21 #include "pStatTimer.h"
22 #include "clockObject.h"
23 #include "config_event.h"
24 #include <algorithm>
25 
26 AsyncTaskManager *AsyncTaskManager::_global_ptr = NULL;
27 
28 TypeHandle AsyncTaskManager::_type_handle;
29 
30 ////////////////////////////////////////////////////////////////////
31 // Function: AsyncTaskManager::Constructor
32 // Access: Published
33 // Description:
34 ////////////////////////////////////////////////////////////////////
35 AsyncTaskManager::
36 AsyncTaskManager(const string &name) :
37  Namable(name),
38  _lock("AsyncTaskManager::_lock"),
39  _num_tasks(0),
40  _clock(ClockObject::get_global_clock()),
41  _frame_cvar(_lock)
42 {
43  // Make a default task chain.
44  do_make_task_chain("default");
45 }
46 
47 ////////////////////////////////////////////////////////////////////
48 // Function: AsyncTaskManager::Destructor
49 // Access: Published, Virtual
50 // Description:
51 ////////////////////////////////////////////////////////////////////
52 AsyncTaskManager::
53 ~AsyncTaskManager() {
54  cleanup();
55 }
56 
57 ////////////////////////////////////////////////////////////////////
58 // Function: AsyncTaskManager::cleanup
59 // Access: Published
60 // Description: Stops all threads and messily empties the task list.
61 // This is intended to be called on destruction only.
62 ////////////////////////////////////////////////////////////////////
65  MutexHolder holder(_lock);
66 
67  if (task_cat.is_debug()) {
68  do_output(task_cat.debug());
69  task_cat.debug(false)
70  << ": cleanup()\n";
71  }
72 
73  // Iterate carefully in case the tasks adjust the chain list within
74  // cleanup().
75  while (!_task_chains.empty()) {
76  PT(AsyncTaskChain) chain = _task_chains[_task_chains.size() - 1];
77  _task_chains.pop_back();
78  chain->do_cleanup();
79  }
80 
81  // There might be one remaining task, the current task. Especially
82  // if it wasn't running on a thread.
83  if (_num_tasks == 1) {
84  nassertv(_tasks_by_name.size() == 1);
85  TasksByName::const_iterator tbni = _tasks_by_name.begin();
86  AsyncTask *task = (*tbni);
87  nassertv(task->_state == AsyncTask::S_servicing ||
88  task->_state == AsyncTask::S_servicing_removed);
89  task->_state = AsyncTask::S_servicing_removed;
90 
91  } else {
92  // If there isn't exactly one remaining task, there should be
93  // none.
94 #ifndef NDEBUG
95  nassertd(_num_tasks == 0 && _tasks_by_name.empty()) {
96  task_cat.error()
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();
101  ++tbni) {
102  task_cat.error()
103  << " " << *(*tbni) << "\n";
104  }
105  }
106 #endif // NDEBUG
107  }
108 }
109 
110 ////////////////////////////////////////////////////////////////////
111 // Function: AsyncTaskManager::get_num_task_chains
112 // Access: Published
113 // Description: Returns the number of different task chains.
114 ////////////////////////////////////////////////////////////////////
117  MutexHolder holder(_lock);
118  return _task_chains.size();
119 }
120 
121 ////////////////////////////////////////////////////////////////////
122 // Function: AsyncTaskManager::get_task_chain
123 // Access: Published
124 // Description: Returns the nth task chain.
125 ////////////////////////////////////////////////////////////////////
127 get_task_chain(int n) const {
128  MutexHolder holder(_lock);
129  nassertr(n >= 0 && n < (int)_task_chains.size(), NULL);
130  return _task_chains[n];
131 }
132 
133 ////////////////////////////////////////////////////////////////////
134 // Function: AsyncTaskManager::make_task_chain
135 // Access: Published
136 // Description: Creates a new AsyncTaskChain of the indicated name
137 // and stores it within the AsyncTaskManager. If a task
138 // chain with this name already exists, returns it
139 // instead.
140 ////////////////////////////////////////////////////////////////////
142 make_task_chain(const string &name) {
143  MutexHolder holder(_lock);
144  return do_make_task_chain(name);
145 }
146 
147 ////////////////////////////////////////////////////////////////////
148 // Function: AsyncTaskManager::find_task_chain
149 // Access: Protected
150 // Description: Searches a new AsyncTaskChain of the indicated name
151 // and returns it if it exists, or NULL otherwise.
152 ////////////////////////////////////////////////////////////////////
154 find_task_chain(const string &name) {
155  MutexHolder holder(_lock);
156  return do_find_task_chain(name);
157 }
158 
159 ////////////////////////////////////////////////////////////////////
160 // Function: AsyncTaskManager::remove_task_chain
161 // Access: Protected
162 // Description: Removes the AsyncTaskChain of the indicated name.
163 // If the chain still has tasks, this will block until
164 // all tasks are finished.
165 //
166 // Returns true if successful, or false if the chain did
167 // not exist.
168 ////////////////////////////////////////////////////////////////////
170 remove_task_chain(const string &name) {
171  MutexHolder holder(_lock);
172 
173  PT(AsyncTaskChain) chain = new AsyncTaskChain(this, name);
174  TaskChains::iterator tci = _task_chains.find(chain);
175  if (tci == _task_chains.end()) {
176  // No chain.
177  return false;
178  }
179 
180  chain = (*tci);
181 
182  while (chain->_num_tasks != 0) {
183  // Still has tasks.
184  task_cat.info()
185  << "Waiting for tasks on chain " << name << " to finish.\n";
186  chain->do_wait_for_tasks();
187  }
188 
189  // Safe to remove.
190  chain->do_cleanup();
191  _task_chains.erase(tci);
192  return true;
193 }
194 
195 ////////////////////////////////////////////////////////////////////
196 // Function: AsyncTaskManager::add
197 // Access: Published
198 // Description: Adds the indicated task to the active queue. It is
199 // an error if the task is already added to this or any
200 // other active queue.
201 ////////////////////////////////////////////////////////////////////
203 add(AsyncTask *task) {
204  nassertv(task->is_runnable());
205 
206  {
207  MutexHolder holder(_lock);
208 
209  if (task_cat.is_debug()) {
210  task_cat.debug()
211  << "Adding " << *task << "\n";
212  }
213 
214  if (task->_state == AsyncTask::S_servicing_removed) {
215  if (task->_manager == this) {
216  // Re-adding a self-removed task; this just means clearing the
217  // removed flag.
218  task->_state = AsyncTask::S_servicing;
219  return;
220  }
221  }
222 
223  nassertv(task->_manager == NULL &&
224  task->_state == AsyncTask::S_inactive);
225  nassertv(!do_has_task(task));
226 
227  _lock.release();
228  task->upon_birth(this);
229  _lock.acquire();
230  nassertv(task->_manager == NULL &&
231  task->_state == AsyncTask::S_inactive);
232  nassertv(!do_has_task(task));
233 
234  AsyncTaskChain *chain = do_find_task_chain(task->_chain_name);
235  if (chain == (AsyncTaskChain *)NULL) {
236  task_cat.warning()
237  << "Creating implicit AsyncTaskChain " << task->_chain_name
238  << " for " << get_type() << " " << get_name() << "\n";
239  chain = do_make_task_chain(task->_chain_name);
240  }
241  chain->do_add(task);
242  }
243 }
244 
245 ////////////////////////////////////////////////////////////////////
246 // Function: AsyncTaskManager::has_task
247 // Access: Published
248 // Description: Returns true if the indicated task has been added to
249 // this AsyncTaskManager, false otherwise.
250 ////////////////////////////////////////////////////////////////////
252 has_task(AsyncTask *task) const {
253  MutexHolder holder(_lock);
254 
255  if (task->_manager != this) {
256  nassertr(!do_has_task(task), false);
257  return false;
258  }
259 
260  if (task->_state == AsyncTask::S_servicing_removed) {
261  return false;
262  }
263 
264  // The task might not actually be in the active queue, since it
265  // might be being serviced right now. That's OK.
266  return true;
267 }
268 
269 ////////////////////////////////////////////////////////////////////
270 // Function: AsyncTaskManager::find_task
271 // Access: Published
272 // Description: Returns the first task found with the indicated name,
273 // or NULL if there is no task with the indicated name.
274 //
275 // If there are multiple tasks with the same name,
276 // returns one of them arbitrarily.
277 ////////////////////////////////////////////////////////////////////
279 find_task(const string &name) const {
280  AsyncTask sample_task(name);
281  sample_task.local_object();
282 
283  TasksByName::const_iterator tbni = _tasks_by_name.lower_bound(&sample_task);
284  if (tbni != _tasks_by_name.end() && (*tbni)->get_name() == name) {
285  return (*tbni);
286  }
287 
288  return NULL;
289 }
290 
291 ////////////////////////////////////////////////////////////////////
292 // Function: AsyncTaskManager::find_tasks
293 // Access: Published
294 // Description: Returns the list of tasks found with the indicated
295 // name.
296 ////////////////////////////////////////////////////////////////////
298 find_tasks(const string &name) const {
299  AsyncTask sample_task(name);
300  sample_task.local_object();
301 
302  TasksByName::const_iterator tbni = _tasks_by_name.lower_bound(&sample_task);
303  AsyncTaskCollection result;
304  while (tbni != _tasks_by_name.end() && (*tbni)->get_name() == name) {
305  result.add_task(*tbni);
306  ++tbni;
307  }
308 
309  return result;
310 }
311 
312 ////////////////////////////////////////////////////////////////////
313 // Function: AsyncTaskManager::find_tasks_matching
314 // Access: Published
315 // Description: Returns the list of tasks found whose name matches
316 // the indicated glob pattern, e.g. "my_task_*".
317 ////////////////////////////////////////////////////////////////////
319 find_tasks_matching(const GlobPattern &pattern) const {
320  string prefix = pattern.get_const_prefix();
321  AsyncTask sample_task(prefix);
322  sample_task.local_object();
323 
324  TasksByName::const_iterator tbni = _tasks_by_name.lower_bound(&sample_task);
325  AsyncTaskCollection result;
326  while (tbni != _tasks_by_name.end() && (*tbni)->get_name().substr(0, prefix.size()) == prefix) {
327  AsyncTask *task = (*tbni);
328  if (pattern.matches(task->get_name())) {
329  result.add_task(task);
330  }
331  ++tbni;
332  }
333 
334  return result;
335 }
336 
337 ////////////////////////////////////////////////////////////////////
338 // Function: AsyncTaskManager::remove
339 // Access: Published
340 // Description: Removes the indicated task from the active queue.
341 // Returns true if the task is successfully removed, or
342 // false if it wasn't there.
343 ////////////////////////////////////////////////////////////////////
346  // We pass this up to the multi-task remove() flavor. Do we care
347  // about the tiny cost of creating an AsyncTaskCollection here?
348  // Probably not.
349  AsyncTaskCollection tasks;
350  tasks.add_task(task);
351  return remove(tasks) != 0;
352 }
353 
354 ////////////////////////////////////////////////////////////////////
355 // Function: AsyncTaskManager::remove
356 // Access: Published
357 // Description: Removes all of the tasks in the AsyncTaskCollection.
358 // Returns the number of tasks removed.
359 ////////////////////////////////////////////////////////////////////
362  MutexHolder holder(_lock);
363  int num_removed = 0;
364 
365  int num_tasks = tasks.get_num_tasks();
366  int i;
367  for (i = 0; i < num_tasks; ++i) {
368  PT(AsyncTask) task = tasks.get_task(i);
369 
370  if (task->_manager != this) {
371  // Not a member of this manager, or already removed.
372  nassertr(!do_has_task(task), num_removed);
373  } else {
374  nassertr(task->_chain->_manager == this, num_removed);
375  if (task_cat.is_debug()) {
376  task_cat.debug()
377  << "Removing " << *task << "\n";
378  }
379  if (task->_chain->do_remove(task)) {
380  _lock.release();
381  task->upon_death(this, false);
382  _lock.acquire();
383  ++num_removed;
384  } else {
385  if (task_cat.is_debug()) {
386  task_cat.debug()
387  << " (unable to remove " << *task << ")\n";
388  }
389  }
390  }
391  }
392 
393  return num_removed;
394 }
395 
396 ////////////////////////////////////////////////////////////////////
397 // Function: AsyncTaskManager::wait_for_tasks
398 // Access: Published
399 // Description: Blocks until the task list is empty.
400 ////////////////////////////////////////////////////////////////////
403  MutexHolder holder(_lock);
404 
405  // Wait for each of our task chains to finish.
406  while (_num_tasks > 0) {
407  // We iterate through with an index, rather than with an iterator,
408  // because it's possible for a task to adjust the task_chain list
409  // during its execution.
410  for (unsigned int i = 0; i < _task_chains.size(); ++i) {
411  AsyncTaskChain *chain = _task_chains[i];
412  chain->do_wait_for_tasks();
413  }
414  }
415 }
416 
417 ////////////////////////////////////////////////////////////////////
418 // Function: AsyncTaskManager::stop_threads
419 // Access: Published
420 // Description: Stops any threads that are currently running. If any
421 // tasks are still pending and have not yet been picked
422 // up by a thread, they will not be serviced unless
423 // poll() or start_threads() is later called.
424 ////////////////////////////////////////////////////////////////////
427  MutexHolder holder(_lock);
428 
429  // We iterate through with an index, rather than with an iterator,
430  // because it's possible for a task to adjust the task_chain list
431  // during its execution.
432  for (unsigned int i = 0; i < _task_chains.size(); ++i) {
433  AsyncTaskChain *chain = _task_chains[i];
434  chain->do_stop_threads();
435  }
436 }
437 
438 ////////////////////////////////////////////////////////////////////
439 // Function: AsyncTaskManager::start_threads
440 // Access: Published
441 // Description: Starts any requested threads to service the tasks on
442 // the queue. This is normally not necessary, since
443 // adding a task will start the threads automatically.
444 ////////////////////////////////////////////////////////////////////
447  MutexHolder holder(_lock);
448 
449  // We iterate through with an index, rather than with an iterator,
450  // because it's possible for a task to adjust the task_chain list
451  // during its execution.
452  for (unsigned int i = 0; i < _task_chains.size(); ++i) {
453  AsyncTaskChain *chain = _task_chains[i];
454 
455  chain->do_start_threads();
456  }
457 }
458 
459 ////////////////////////////////////////////////////////////////////
460 // Function: AsyncTaskManager::get_tasks
461 // Access: Published
462 // Description: Returns the set of tasks that are active or sleeping
463 // on the task manager, at the time of the call.
464 ////////////////////////////////////////////////////////////////////
466 get_tasks() const {
467  MutexHolder holder(_lock);
468 
469  AsyncTaskCollection result;
470  TaskChains::const_iterator tci;
471  for (tci = _task_chains.begin();
472  tci != _task_chains.end();
473  ++tci) {
474  AsyncTaskChain *chain = (*tci);
475  result.add_tasks_from(chain->do_get_active_tasks());
476  result.add_tasks_from(chain->do_get_sleeping_tasks());
477  }
478 
479  return result;
480 }
481 
482 ////////////////////////////////////////////////////////////////////
483 // Function: AsyncTaskManager::get_active_tasks
484 // Access: Published
485 // Description: Returns the set of tasks that are active (and not
486 // sleeping) on the task manager, at the time of the
487 // call.
488 ////////////////////////////////////////////////////////////////////
491  MutexHolder holder(_lock);
492 
493  AsyncTaskCollection result;
494  TaskChains::const_iterator tci;
495  for (tci = _task_chains.begin();
496  tci != _task_chains.end();
497  ++tci) {
498  AsyncTaskChain *chain = (*tci);
499  result.add_tasks_from(chain->do_get_active_tasks());
500  }
501 
502  return result;
503 }
504 
505 ////////////////////////////////////////////////////////////////////
506 // Function: AsyncTaskManager::get_sleeping_tasks
507 // Access: Published
508 // Description: Returns the set of tasks that are sleeping (and not
509 // active) on the task manager, at the time of the
510 // call.
511 ////////////////////////////////////////////////////////////////////
514  MutexHolder holder(_lock);
515 
516  AsyncTaskCollection result;
517  TaskChains::const_iterator tci;
518  for (tci = _task_chains.begin();
519  tci != _task_chains.end();
520  ++tci) {
521  AsyncTaskChain *chain = (*tci);
522  result.add_tasks_from(chain->do_get_sleeping_tasks());
523  }
524 
525  return result;
526 }
527 
528 ////////////////////////////////////////////////////////////////////
529 // Function: AsyncTaskManager::poll
530 // Access: Published
531 // Description: Runs through all the tasks in the task list, once, if
532 // the task manager is running in single-threaded mode
533 // (no threads available). This method does nothing in
534 // threaded mode, so it may safely be called in either
535 // case.
536 ////////////////////////////////////////////////////////////////////
538 poll() {
539  MutexHolder holder(_lock);
540 
541  // We iterate through with an index, rather than with an iterator,
542  // because it's possible for a task to adjust the task_chain list
543  // during its execution.
544  for (unsigned int i = 0; i < _task_chains.size(); ++i) {
545  AsyncTaskChain *chain = _task_chains[i];
546  chain->do_poll();
547  }
548 
549  // Just in case the clock was ticked explicitly by one of our
550  // polling chains.
551  _frame_cvar.notify_all();
552 }
553 
554 ////////////////////////////////////////////////////////////////////
555 // Function: AsyncTaskManager::get_next_wake_time
556 // Access: Published
557 // Description: Returns the scheduled time (on the manager's clock)
558 // of the next sleeping task, on any task chain, to
559 // awaken. Returns -1 if there are no sleeping tasks.
560 ////////////////////////////////////////////////////////////////////
561 double AsyncTaskManager::
563  MutexHolder holder(_lock);
564 
565  bool got_any = false;
566  double next_wake_time = -1.0;
567 
568  TaskChains::const_iterator tci;
569  for (tci = _task_chains.begin();
570  tci != _task_chains.end();
571  ++tci) {
572  AsyncTaskChain *chain = (*tci);
573  double time = chain->do_get_next_wake_time();
574  if (time >= 0.0) {
575  if (!got_any) {
576  got_any = true;
577  next_wake_time = time;
578  } else {
579  next_wake_time = min(time, next_wake_time);
580  }
581  }
582  }
583 
584  return next_wake_time;
585 }
586 
587 ////////////////////////////////////////////////////////////////////
588 // Function: AsyncTaskManager::output
589 // Access: Published, Virtual
590 // Description:
591 ////////////////////////////////////////////////////////////////////
592 void AsyncTaskManager::
593 output(ostream &out) const {
594  MutexHolder holder(_lock);
595  do_output(out);
596 }
597 
598 ////////////////////////////////////////////////////////////////////
599 // Function: AsyncTaskManager::write
600 // Access: Published, Virtual
601 // Description:
602 ////////////////////////////////////////////////////////////////////
603 void AsyncTaskManager::
604 write(ostream &out, int indent_level) const {
605  MutexHolder holder(_lock);
606  indent(out, indent_level)
607  << get_type() << " " << get_name() << "\n";
608 
609  TaskChains::const_iterator tci;
610  for (tci = _task_chains.begin();
611  tci != _task_chains.end();
612  ++tci) {
613  AsyncTaskChain *chain = (*tci);
614  if (chain->_num_tasks != 0) {
615  out << "\n";
616  chain->do_write(out, indent_level + 2);
617  }
618  }
619 }
620 
621 ////////////////////////////////////////////////////////////////////
622 // Function: AsyncTaskManager::do_make_task_chain
623 // Access: Protected
624 // Description: Creates a new AsyncTaskChain of the indicated name
625 // and stores it within the AsyncTaskManager. If a task
626 // chain with this name already exists, returns it
627 // instead.
628 //
629 // Assumes the lock is held.
630 ////////////////////////////////////////////////////////////////////
631 AsyncTaskChain *AsyncTaskManager::
632 do_make_task_chain(const string &name) {
633  PT(AsyncTaskChain) chain = new AsyncTaskChain(this, name);
634 
635  TaskChains::const_iterator tci = _task_chains.insert(chain).first;
636  return (*tci);
637 }
638 
639 ////////////////////////////////////////////////////////////////////
640 // Function: AsyncTaskManager::do_find_task_chain
641 // Access: Protected
642 // Description: Searches a new AsyncTaskChain of the indicated name
643 // and returns it if it exists, or NULL otherwise.
644 //
645 // Assumes the lock is held.
646 ////////////////////////////////////////////////////////////////////
648 do_find_task_chain(const string &name) {
649  PT(AsyncTaskChain) chain = new AsyncTaskChain(this, name);
650 
651  TaskChains::const_iterator tci = _task_chains.find(chain);
652  if (tci != _task_chains.end()) {
653  return (*tci);
654  }
655 
656  return NULL;
657 }
658 
659 ////////////////////////////////////////////////////////////////////
660 // Function: AsyncTaskManager::remove_task_by_name
661 // Access: Protected
662 // Description: Removes the task from the _tasks_by_name index, if it
663 // has a nonempty name.
664 ////////////////////////////////////////////////////////////////////
665 void AsyncTaskManager::
666 remove_task_by_name(AsyncTask *task) {
667  if (!task->get_name().empty()) {
668  // We have to scan linearly through all of the tasks with the same
669  // name.
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);
674  return;
675  }
676  if ((*tbni)->get_name() != task->get_name()) {
677  // Too far.
678  break;
679  }
680 
681  ++tbni;
682  }
683 
684  // For some reason, the task wasn't on the index.
685  nassertv(false);
686  }
687 }
688 
689 ////////////////////////////////////////////////////////////////////
690 // Function: AsyncTaskManager::do_has_task
691 // Access: Protected
692 // Description: Returns true if the task is on one of the task lists,
693 // false if it is not (false may mean that the task is
694 // currently being serviced). Assumes the lock is
695 // currently held.
696 ////////////////////////////////////////////////////////////////////
697 bool AsyncTaskManager::
698 do_has_task(AsyncTask *task) const {
699  TaskChains::const_iterator tci;
700  for (tci = _task_chains.begin();
701  tci != _task_chains.end();
702  ++tci) {
703  AsyncTaskChain *chain = (*tci);
704  if (chain->do_has_task(task)) {
705  return true;
706  }
707  }
708 
709  return false;
710 }
711 
712 ////////////////////////////////////////////////////////////////////
713 // Function: AsyncTaskManager::do_output
714 // Access: Protected, Virtual
715 // Description:
716 ////////////////////////////////////////////////////////////////////
717 void AsyncTaskManager::
718 do_output(ostream &out) const {
719  out << get_type() << " " << get_name()
720  << "; " << _num_tasks << " tasks";
721 }
722 
723 ////////////////////////////////////////////////////////////////////
724 // Function: AsyncTaskManager::make_global_ptr
725 // Access: Private, Static
726 // Description: Called once per application to create the global
727 // task manager object.
728 ////////////////////////////////////////////////////////////////////
729 void AsyncTaskManager::
730 make_global_ptr() {
731  nassertv(_global_ptr == (AsyncTaskManager *)NULL);
732 
733  _global_ptr = new AsyncTaskManager("TaskManager");
734  _global_ptr->ref();
735 }
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.
Definition: globPattern.I:157
A lightweight C++ object whose constructor calls acquire() and whose destructor calls release() on a ...
Definition: mutexHolder.h:29
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.
Definition: globPattern.cxx:57
void acquire() const
Grabs the mutex if it is available.
Definition: mutexDirect.I:70
int get_num_task_chains() const
Returns the number of different task chains.
A base class for all things which can have a name.
Definition: namable.h:29
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.
Definition: clockObject.h:66
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.
Definition: mutexDirect.I:99
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.
Definition: asyncTask.h:43
double get_next_wake_time() const
Returns the scheduled time (on the manager&#39;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.
Definition: typeHandle.h:85
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...
Definition: globPattern.h:37
void poll()
Runs through all the tasks in the task list, once, if the task manager is running in single-threaded ...