historical/toontown-classic.git/panda/include/asyncTaskChain.h
2024-01-16 11:20:27 -06:00

230 lines
6.7 KiB
C++

/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file asyncTaskChain.h
* @author drose
* @date 2006-08-23
*/
#ifndef ASYNCTASKCHAIN_H
#define ASYNCTASKCHAIN_H
#include "pandabase.h"
#include "asyncTask.h"
#include "asyncTaskCollection.h"
#include "typedReferenceCount.h"
#include "thread.h"
#include "conditionVar.h"
#include "pvector.h"
#include "pdeque.h"
#include "pStatCollector.h"
#include "clockObject.h"
class AsyncTaskManager;
/**
* The AsyncTaskChain is a subset of the AsyncTaskManager. Each chain
* maintains a separate list of tasks, and will execute them with its own set
* of threads. Each chain may thereby operate independently of the other
* chains.
*
* The AsyncTaskChain will spawn a specified number of threads (possibly 0) to
* serve the tasks. If there are no threads, you must call poll() from time
* to time to serve the tasks in the main thread. Normally this is done by
* calling AsyncTaskManager::poll().
*
* Each task will run exactly once each epoch. Beyond that, the tasks' sort
* and priority values control the order in which they are run: tasks are run
* in increasing order by sort value, and within the same sort value, they are
* run roughly in decreasing order by priority value, with some exceptions for
* parallelism. Tasks with different sort values are never run in parallel
* together, but tasks with different priority values might be (if there is
* more than one thread).
*/
class EXPCL_PANDA_EVENT AsyncTaskChain : public TypedReferenceCount, public Namable {
public:
AsyncTaskChain(AsyncTaskManager *manager, const std::string &name);
~AsyncTaskChain();
PUBLISHED:
void set_tick_clock(bool tick_clock);
bool get_tick_clock() const;
BLOCKING void set_num_threads(int num_threads);
int get_num_threads() const;
int get_num_running_threads() const;
BLOCKING void set_thread_priority(ThreadPriority priority);
ThreadPriority get_thread_priority() const;
void set_frame_budget(double frame_budget);
double get_frame_budget() const;
void set_frame_sync(bool frame_sync);
bool get_frame_sync() const;
void set_timeslice_priority(bool timeslice_priority);
bool get_timeslice_priority() const;
BLOCKING void stop_threads();
void start_threads();
INLINE bool is_started() const;
bool has_task(AsyncTask *task) const;
BLOCKING void wait_for_tasks();
int get_num_tasks() const;
AsyncTaskCollection get_tasks() const;
AsyncTaskCollection get_active_tasks() const;
AsyncTaskCollection get_sleeping_tasks() const;
void poll();
double get_next_wake_time() const;
virtual void output(std::ostream &out) const;
virtual void write(std::ostream &out, int indent_level = 0) const;
protected:
class AsyncTaskChainThread;
typedef pvector< PT(AsyncTask) > TaskHeap;
void do_add(AsyncTask *task);
bool do_remove(AsyncTask *task, bool upon_death=false);
void do_wait_for_tasks();
void do_cleanup();
bool do_has_task(AsyncTask *task) const;
int find_task_on_heap(const TaskHeap &heap, AsyncTask *task) const;
void service_one_task(AsyncTaskChainThread *thread);
void cleanup_task(AsyncTask *task, bool upon_death, bool clean_exit);
bool finish_sort_group();
void filter_timeslice_priority();
void do_stop_threads();
void do_start_threads();
AsyncTaskCollection do_get_active_tasks() const;
AsyncTaskCollection do_get_sleeping_tasks() const;
void do_poll();
void cleanup_pickup_mode();
INLINE double do_get_next_wake_time() const;
static INLINE double get_wake_time(AsyncTask *task);
void do_output(std::ostream &out) const;
void do_write(std::ostream &out, int indent_level) const;
void write_task_line(std::ostream &out, int indent_level, AsyncTask *task, double now) const;
protected:
class AsyncTaskChainThread : public Thread {
public:
AsyncTaskChainThread(const std::string &name, AsyncTaskChain *chain);
virtual void thread_main();
AsyncTaskChain *_chain;
AsyncTask *_servicing;
};
class AsyncTaskSortWakeTime {
public:
bool operator () (AsyncTask *a, AsyncTask *b) const {
return AsyncTaskChain::get_wake_time(a) > AsyncTaskChain::get_wake_time(b);
}
};
class AsyncTaskSortPriority {
public:
bool operator () (AsyncTask *a, AsyncTask *b) const {
if (a->get_sort() != b->get_sort()) {
return a->get_sort() > b->get_sort();
}
if (a->get_priority() != b->get_priority()) {
return a->get_priority() < b->get_priority();
}
if (a->get_start_time() != b->get_start_time()) {
return a->get_start_time() > b->get_start_time();
}
// Failing any other ordering criteria, we sort the tasks based on the
// order in which they were added to the task chain.
return a->_implicit_sort > b->_implicit_sort;
}
};
typedef pvector< PT(AsyncTaskChainThread) > Threads;
AsyncTaskManager *_manager;
ConditionVar _cvar; // signaled when one of the task heaps, _state, or _current_sort changes, or a task finishes.
enum State {
S_initial, // no threads yet
S_started, // threads have been started
S_interrupted, // task returned DS_interrupt, requested from sub-thread.
S_shutdown // waiting for thread shutdown, requested from main thread
};
bool _tick_clock;
bool _timeslice_priority;
int _num_threads;
ThreadPriority _thread_priority;
Threads _threads;
double _frame_budget;
bool _frame_sync;
int _num_busy_threads;
int _num_tasks;
int _num_awaiting_tasks;
TaskHeap _active;
TaskHeap _this_active;
TaskHeap _next_active;
TaskHeap _sleeping;
State _state;
int _current_sort;
bool _pickup_mode;
bool _needs_cleanup;
int _current_frame;
double _time_in_frame;
bool _block_till_next_frame;
unsigned int _next_implicit_sort;
static PStatCollector _task_pcollector;
static PStatCollector _wait_pcollector;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
TypedReferenceCount::init_type();
register_type(_type_handle, "AsyncTaskChain",
TypedReferenceCount::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
friend class AsyncFuture;
friend class AsyncTaskChainThread;
friend class AsyncTask;
friend class AsyncTaskManager;
friend class AsyncTaskSortWakeTime;
};
INLINE std::ostream &operator << (std::ostream &out, const AsyncTaskChain &chain) {
chain.output(out);
return out;
};
#include "asyncTaskChain.I"
#endif